Blended Algebraic and Denotational Semantics for Adt Languages with Mutable Objects Blended Algebraic and Denotational Semantics for Adt Languages with Mutable Objects

نویسندگان

  • Gary T. Leavens
  • Krishna Kishore Dhara
چکیده

Syntax: P 2 Program TD 2 Type-Declaration T, S, U 2 Type-Name MD 2 Method-Declaration F* 2 Formal-List F 2 Formal B 2 Body D 2 Declaration E 2 Expression g 2 Method-Name E* 2 Expression-List C 2 Command M 2 Main I 2 Identi er N 2 Numeric-literal P ::= TD MD M TD ::= j type I fields ( F* ) j TD1 ; TD2 FD ::= j I : T j FD1 ; FD2 T ::= I MD ::= j method I ( F* ) : T f B g j MD1 ; MD2 F* ::= j F F* F ::= I : T B ::= D C ; return E D ::= j const I : T = E j D1 ; D2 E ::= I j N j true j false j nothing j g(E*) j new T(E*) j I1 . I2 g ::= I E* ::= j E* E C ::= E j I1 . I2 := E j C1; C2 j if E1 then C1 else C2 fi M ::= main f observe D1 C1 by C2 D2 g Figure 1: Abstract syntax of . In concrete examples, we separate elements of formal lists and expression lists with commas. semantics, we present an example of the semantics and discuss the technique. 2.1 Syntax and Overview of The abstract syntax of is given in Figure 1. A program consists of type de nitions, method de nitions, and a main procedure. Informally the program runs by elaborating the declarations of types, and methods, and then running the main procedure. The types the user can de ne are all represented by records; for simplicity, there is no built-in variant representation. The objects of such a type can be mutated if desired, because the elds can be assigned within a method by the eld assignment command (of the form \I1.I2 := E"). The eld assignment command, and the object creation (\new T(E*)") and eld access (\I1 . I2") expressions can only be used directly within methods; this provides a simple form of information hiding. For better information hiding, a module system could be added, but it would complicate the semantics. 3 The language is rst-order: for simplicity there is no lambda abstraction or type polymorphism. Also for simplicity, there is no recursion. Methods return the result of the last expression in their bodies; if nothing is to be returned, the built-in constant nothing may be used to return the only value of the built-in type Void. (The constant nothing may also be used as a command, in which case it acts like skip.) For simplicity, the only declaration form binds a name to the result of an expression (an object). Such bindings cannot be changed, and are therefore constant bindings. This is not a great restriction, however, as the programmer can de ne any desired type of variables by de ning objects with one eld. (This is similar to the way variables are treated in, for example, SML [41] [50].) For example, the following shows how one would write integer variables. type IntVar fields (val: Int); method mkIntVar(e:Int): Void { nothing; return new IntVar(e) }; method assign(v:IntVar, e:Int): Void { v.val := e; return nothing }; method read(v:IntVar): Int { nothing; return v.val }; The form of a main procedure is unusual, because it is split into two parts; the declaration and command between the keywords observe and by (D1 and C1) de ne a state which the following command and declaration (C2 and D2) observe. The nal declaration, D2, may only declare constants of types Int or Bool. For simplicity, the \output" of the main procedure (and hence the program) is de ned to be the values of the constants in D2. The split of the main procedure into two parts is motivated by our studies of behavioral subtyping [32] [28] [30]. Informally, OO programmers often add new subtypes of existing types to a running program, with the expectation that once objects of the new subtypes are created the rest of the program will continue running as before. The behavior will be \enhanced" but nothing should break in the unchanged code. Thus the rst declaration and command in the main procedure model the part of the program that is changed by the addition of new types (new type and method de nitions would be added as well). The second command and declaration in the main procedure model the part of the program that is unchanged by the addition of the new types. In this paper, since we are ignoring subtyping, we will use this split to study representation independence: replacing one algebraic model of the types with another, and seeing how the observation (the second command and declaration) are a ected. The split will also make clear how the denotations for command are parameterized by an algebraic structure. However, such a split main procedure is not necessary for our semantic techniques. As will be shown below, one can just run the rst part of the main procedure, and then the second. Figure 2 is a complete example program. It declares two types: Point and Rect (rectangle). Of the methods, mkRect is the most complex; it declares a constant, r, which is bound to a new rectangle object, with the eld bl initialized to the object p1 and tr initialized to p2. (The actual arguments in object creation expression, \new T (E*)", are bound to the elds in the order in which the elds are declared.) If the point p2 is not towards top and right of p1, then r is mutated so that its eld bl becomes p2, and tr becomes p1. Parameter passing does not make copies; hence any other names for the arguments to mkRect outside that method become aliases. (Similarly, eld assignments do not make copies.) The methods botLeft and topRight also do not make copies when they return their results. This is poor programming practice, but it helps us illustrate how the language allows mutation and aliasing. For example, at the end of the rst part of the main procedure, just before the keyword \by", x and y are aliases, as are botLeft(x), botLeft(y), and botLeft(w). 4 Hence, the horizMove(w, 1) adds 1 to the abscissa of the point which is botLeft(w) and also botLeft(y) and botLeft(x). Similarly, vertMove(x) adds 1 to the ordinate of this point, and also adds 1 to the ordinate of z. Thus the output values are appropriate for their names in Figure 2. 2.2 Semantics of The fundamental idea of our semantic technique is to split the semantics of a language into two parts: an algebraic structure, and a denotational semantics that computes using the algebraic structure. This is illustrated in Figure 3. Here one sees that the denotation of types and methods resides in the algebra. The denotational part handles the manipulation of the program state (environment and store), and gives the semantics to commands and expressions. The denotational part relies on the algebra for invoking methods. The signature ( ) of the algebra thus documents the interface between the denotational part of the semantics and the algebraic part. Neither the algebra nor the denotational parts of the semantics are completely una ected by the other. One interaction comes from the treatment of the store. To handle mutation and aliasing, the algebra uses the store that the denotational part maintains for it; when a method is invoked, it receives a store, and returns a modi ed store. Therefore, in a sense, an algebra is not really an \algebra" at all, because it is not closed in the sense that its methods take and return a store, but the store is not itself part of the algebra. This is done in order to keep the meaning of the algebra xed and the semantics of the algebra's methods purely functional. If the store were part of the algebra, then the algebra would change (evolve, as in [21] [22]), but then the denotational semantics would lose its characteristic referential transparency; that is, the denotational semantics would no longer be written over a purely functional base. The other interaction is that when elaborating the method declarations, the denotational semantics is used to give meaning to the body of a method. We will see, however, that the semantic clauses for declarations, commands, and expressions, are parametrized with respect to an algebra, and thus there is still great deal of separation. Some terminological remarks may also be in order before going into the details of the semantics. As is usual in denotational semantics, mutable objects are modeled using locations (memory cells). In other words, our model of an object is a typed location. Locations are typed in the sense that a location l : T can only store a value of type T . Each object (location) contains a value, sometimes called an \abstract value" [24], which can be extracted by a store mapping, as is usual in denotational semantics [57]. (This resembles Schei er's denotational semantics of CLU [56], and would be similar to a semantics of LISP.) An object may \contain" other objects, if its value contains other locations. The main procedure in a program, however, does not have direct access to locations that may be contained in an abstract value, but can only access locations and abstract values in ways permitted by the algebra's operations. For simplicity, we do not worry about garbage collection in the semantics. 2.2.1 Visible Types and External Values To facilitate the study of visible behavior, we distinguish a subset of types as visible types; these are the types of values that can be \output" by a program [60] [46]. These are de ned 5 type Point fields (x:Int, y:Int); type Rect fields (bl:Point, tr:Int); method mkPoint (i:Int, j:Int):Point { const p:Point = new Point(i, j); return p }; method abscissa (p:Point):Int { nothing; return p.x }; method ordinate (p:Point):Int { nothing; return p.y }; method addX (p:Point, i:Int):Void { p.x := add(p.x, i); return nothing }; method addY (p:Point, i:Int):Void { p.y := add(p.y, i); return nothing }; method upRightOf (p1:Point, p2:Point):Bool { nothing; return and(leq(p1.x, p2.x), leq(p1.y, p2.y)) }; method pointEqual (p1:Point, p2:Point): Bool { nothing; return and(equal(abscissa(p1), absicissa(p2)) equal(ordinate(p1), ordinate(p2))) }; method mkRect (p1:Point, p2:Point):Rect { const r:Rect = new Rect(p1 p2); if upRightOf(p1, p2) then nothing else r.bl := p2; r.tr := b1 fi; return r }; method botLeft (r:Rect):Point { nothing; return r.bl }; method topRight (r:Rect):Point { nothing; return r.tr }; method horizMove (r:Rect delta:Int):Void { addX(r.bl, delta); addX(r.tr, delta); return nothing }; method vertMove (r:Rect, delta:Int):Void { addY(r.bl, delta); addY(r.tr, delta); return nothing }; main { observe const z:Point = mkPoint(2, 4); const w:Rect = mkRect(mkPoint(0,0), mkPoint(2,4)); const y:Rect = mkRect(botLeft(w), z); const x:Rect = y; horizMove(w, 1); vertMove(x,1) byif pointEqual(topRight(y), mkPoint(2, 5)) then addX(topRight(w), 1) else nothing fi const shouldBe1:Int = abscissa(botLeft(y)); const shouldBe5:Int = ordinate(z); const shouldBe4:Int = abscissa(topRight(w) } Figure 2: A sample program. When executed, it should terminate with the value 1 in shouldBe1, 5 in shouldBe5, and 4 in shouldBe4. 6 Algebraic Denotational commands expressions types methods Figure 3: A picture that illustrates the idea of the split semantics. as follows. VIS def = fBool; Intg (1) The sets of externally visible values of each of these types is also xed, and are de ned as follows. EXTERNALSBool = ftrue ; falseg (2) EXTERNALSInt = f0; 1; 1; 2; 2; . . .g (3) We write EXTERNALS for SV2VIS EXTERNALSV . 2.2.2 Signatures The interface between our programming language semantics and an ADT model is described by a signature. A signature contains, as usual, a set of type names, and method names. (Method names are historically called operation symbols in this context.) Overloading of operation symbols based on argument types is permitted, because this is needed to permit elds with the same names to be used in di erent representations. It will also be useful in the application of this work to object-oriented programming with message passing (which supports a kind of dynamic overloading [69]). The signatures are thus a simpli ed form of the signatures used in category-sorted algebras [53] [54]. De nition 2.1 (signature) A signature, , is a tuple, (TYPES ;OPS ;ResType), where TYPES is a non-empty set of type symbols, such that both Void 2 TYPES and VIS TYPES, and OPS is a family of sets of operation symbols, indexed by the natural numbers, and 7 TYPES def = fVoid; Bool; Intg OPS and ResType nothing : ()! Void true : ()! Bool false : ()! Bool and : (Bool; Bool)! Bool or : (Bool; Bool)! Bool not : (Bool)! Bool 0 : ()! Int 1 : ()! Int add : (Int; Int)! Int mult : (Int; Int)! Int negate : (Int)! Int equal : (Int; Int)! Bool less : (Int; Int)! Bool leq : (Int; Int)! Bool Figure 4: The signature of the built-in types in . ResType is a family of partial functions indexed by the natural numbers, such that for each natural number n, ResTypen : OPSn TYPESn ! TYPES?. The type Void is used to indicate that a method has no results. To simplify notation we usually write g 2 OPS as shorthand for g 2 Sn2Nat OPSn; and we usually omit the subscript on ResType. An operation symbol g has rank n if g 2 OPSn. If g has rank n and ResType(g; ~ S) = T , then the pair (~ S; T ) is called a type of g, and we write g : ~ S ! T . Because of overloading, an operation symbol may have many types but at most one result type for each tuple of argument types. Example Signatures Figure 4 gives the signature, , of the built-in types in . The denotational semantics for produces a signature for the type and method declarations. This signature contains as a subsignature. As an example, the signature D that would be obtained by elaborating the declarations in Figure 2 is given in Figure 5. Auxiliary Functions on Signatures Because signatures are constructed as part of the denotations of types and methods in , we will need several auxiliary functions on signatures. These are de ned below. We write SIGS for the set of all signatures. SIGS def = f j is a signatureg (4) The notation [i 7! OPS i [ fgg]OPS , denotes the family hOPS 0n : n 2 Nati such that OPS 0i = OPS i[fgg and for all j 6= i, OPS 0j = OPS j . We also write [(g; ~ S) 7! T ]ResType, for 8 TYPESD def = TYPES [ fPoint; Rectg OPSD and ResTypeD added to mkPoint : (Int; Int)! Point abscissa : (Point)! Int ordinate : (Point)! Int addX : (Point; Int)! Void addY : (Point; Int)! Void upRightOf : (Point; Point)! Bool pointEqual : (Point; Point)! Bool mkRect : (Point; Point)! Rect botLeft : (Rect)! Point topRight : (Rect)! Point horizMove : (Rect; Int)! Void vertMove : (Rect; Int)! Void Figure 5: The signature D. The operation symbols of D include all those of and the ones listed above. the family hResType0n : n 2 Nati such that ResType0(g; ~ S) = T , and for all (g0; ~ U) 6= (g; ~ S) ResType0(g0; ~ U) = ResType(g; ~ U). The following auxiliary functions are used to add types and messages (the names and types of methods) to signatures. Both of these functions require the type or message being added to not already be in the signature; this is useful in ensuring that types and methods are not multiply declared in . addType : TYPES ! SIGS ! SIGS? addType[[T ]] (TYPES ;OPS ;ResType) = if T 2 TYPES then ? else (TYPES [ fTg;OPS;ResType) addMessage : Method-Name! TYPES ! TYPES ! SIGS ! SIGS? addMessage[[g]][[~ S]][[T ]] (TYPES ;OPS;ResType) = if ResType(g; ~ S) 6= ? then ? else (TYPES ; [length(~ S) 7! OPS length(~ S) [ fgg]OPS ; [(g; ~ S) 7! T ]ResType) 9 Special message names are used in the semantics below to create objects, and to set and get elds of objects. These messages have names of the form \creator(T)", \getter(I)", and \setter(I)". Later, for purposes of information hiding, we will need to delete these operations from a signature. They are deleted by the auxiliary function hideInternalMessages de ned below. To avoid unnecessary detail, we assume that there is a predicate isToBeHidden, which is true for all message names of the form \creator(T)", \getter(I)", or \setter(I)", and false for all other message names. We write OPS n fg j g 2 OPS ; isToBeHidden(g)g for the obvious Nat -indexed family of operation symbols with such operation symbols removed. We also write ResTypenf(g; ~ S) 7! T j ResType(g; ~ S) = T; isToBeHidden(g)g for the family ResType0 such that ResType0(g; ~ U) = ? if isToBeHidden(g) and ResType0(g; ~ U) = ResType(g; ~ U) otherwise. hideInternalMessages : SIGS ! SIGS hideInternalMessages (TYPES ;OPS ;ResType) = (TYPES; OPS n fg j g 2 OPS ; isToBeHidden(g)g; ResType n f(g; ~ S) 7! T j ResType(g; ~ S) = T; isToBeHidden(g)g) 2.2.3 Algebras and Stores An algebra that presents the interface is called a -algebra. Stores are de ned simultaneously, but are not contained in -algebras. This de nition of algebra and stores below was inspired by work on models of types for interface speci cation languages [73] [8]. To explain a term used in the de nition below, a nite function, f : S n ! T is a function S ! T? such that f has a proper result (not ?) only on a nite number of arguments. By the domain of a nite function, dom(f), we mean the set of all arguments for which f 's result is proper. De nition 2.2 ( -algebra, STORE) A -algebra, A, is a tuple, (SORTSA;ObjectTypesA;LOCSA;VALSA;TtoSA;OPSA; externValA); where SORTSA TYPES is a set of sort symbols, ObjectTypesA TYPES is a set of object type symbols, LOCSA is a family of sets, indexed by ObjectTypesA, representing typed locations, VALSA is a family of abstract values indexed by SORTSA, such that for each T 2 ObjectTypesA, VALSAT = LOCSAT TtoSA : ObjectTypesA ! SORTSA is a function that gives a sort symbol for each object type symbol, OPSA is a family of operation interpretations indexed by the natural numbers such that for each n 2 Nat and g 2 OPSn, there is a polymorphic partial function gA 2 OPSAn where for each ~ S 2 TYPESn and T 2 TYPES, if ResType(g; ~ S) = T then gA satis es gA : (VALSA~ S STORE [A])! (VALSAT STORE [A])?; 10 externValA is a family of functions indexed by VIS, such that for each T 2 VIS, externValAT : VALSAT STORE [A]! (EXTERNALST )?, and STORE [A] def = LOCSA n ! VALSA (5) is such that if : STORE [A], l 2 LOCSAT , and l 2 dom( ), then (l) 2 VALSATtoSA[T ]. An algebra may have more sort symbols than type symbols because it may be convenient to introduce hidden sorts in a model. (So, if we followed Goguen [17], we would call algebras \machines".) The set of object types is the set of types whose objects are modeled by locations. An immutable object might be modeled by a location whose value never changes or might be modeled by a value that is not a location. For each object type, the TtoS mapping gives the sort of its abstract values. A method is modeled by a partial function from a tuple of argument values and an initial store to a result value and a nal store. (The notation VALSA~ S means the cross product of the domains VALSASi , that is length ~ S i=1 VALSASi . For example, VALSA(S1;S2) means VALSAS1 VALSAS2 .) Since methods are modeled by functions, our algebras do not model nondeterministic methods; this is another simpli cation. We require that such functions be polymorphic, because it a ords considerable notational convenience; if we were modeling an object-oriented language with message passing, the polymorphism would be of the essence [33], but in this setting we could excise it at the cost of additional notation. Stores are nite functions because they are not de ned for all potential locations. The store argument to externValAT might be needed if the visible types were object types, and in that case the result might be ?, if the location passed was not in the domain of the store. We use l : T to stand for a location l 2 LOCSAT when the algebra A is clear from context. For this we also write \l : T is a location." Similarly we use v : T to stand for an abstract value v 2 VALSAT . Example Algebras and Auxiliary Functions on Stores Figure 6 gives an example -algebra, which is the built-in algebra for , A . In A the visible types are modeled as abstract values instead of objects. This example also shows how traditional multi-sorted algebras can be adapted to our de nition. A more interesting example algebra, D, is given in Figure 7. It would be the denotation of the types and methods in Figure 2. We use the special names of the form \sortFor(Point)" in the semantics of for the names of sorts. Note that the abstract values of rectangles, VALSDsortFor(Rect), contain point objects (i.e., locations). Because the visible types in D are modeled as pure values instead of objects, D can be thought of as a model of an implementation in a hybrid object-oriented language such as C++, CLOS, or Ei el. The operations of D are shown in Figure 8. In the gure we use the following notation, which we will also use in the semantics. This notation is not speci c to D, but will also be applied to any algebra constructed by our semantics, hence in the de nitions of the notation, D should be thought of as generic. We use nextFree[T ] to nd the next free location of type T in a given store (where TYPES is the set of types in the signature of D): nextFree[T ] : STORE [D]! LOCSDT nextFree[T ] def = lT 1+max(f 1g[fijlSi 2dom( ); S2TYPESg) 11 SORTSA def = TYPES ObjectTypesA def = fg LOCSA is empty TtoSA [T ] is the empty function, for each T VALSA Void def = f g VALSA Bool def = ftrue ; falseg VALSA Int def = f0; 1; 1; 2; 2; . . .g externValA Bool(v; ) def = v externValA Int(v; ) def = v Operation Interpretations nothingA ((); ) def = ( ; ) trueA ((); ) def = (true; ) falseA ((); ) def = (false; ) andA ((v1; v2); ) def = (v1 ^ v2; ) orA ((v1; v2); ) def = (v1 _ v2; ) notA ((v); ) def = (:(v); ) 0A ((); ) def = (0; ) 1A ((); ) def = (1; ) addA ((v1; v2); ) def = (v1 + v2; ) multA ((v1; v2); ) def = (v1 v2; ) negateA ((v); ) def = ( v1; ) equalA ((v1; v2); ) def = (v1 = v2; ) lessA ((v1; v2); ) def = (v1 < v2; ) leqA ((v1; v2); ) def = (v1 v2; ) Figure 6: The -algebra A . In the de nition of SORTSA , TYPES means the TYPES of . 12 SORTSD def = TYPES SfsortFor(Point); sortFor(Rect)g ObjectTypesD def = fPoint; Rectg LOCSDT def = flT i j i 2 Natg; for each T 2 ObjectTypesD Type to Sort Mapping (TtoSD) Point 7! sortFor(Point) Rect 7! sortFor(Rect) VALSDVoid def = VALSA Void VALSDBool def = VALSA Bool VALSDInt def = VALSA Int VALSDsortFor(Point) def = f(vx; vy) j vx; vy 2 VALSDIntg VALSDsortFor(Rect) def = f(lbl; ltr) j lbl; ltr 2 LOCSDPointg and for T 2 ObjectTypesD, VALSDT def = LOCSDT externValD def = externValA Figure 7: The D-algebra D (part 1). In this gure, TYPES is from D. 13 We use the function alloc[T ] to nd a free location and initialize it with an abstract value of type T : alloc[T ] : (VALSDTtoSD[T ] STORE [D])! VALSDT STORE [D] alloc[T ](v; ) def = let l = nextFree[T ]( ) in (l; [l 7! v] ): The notation [l 7! v] is de ned by [l 7! v] def = l2 : if (l2 = l) then v else ( l2): (6) We use emptyStore : STORE [D] for the store whose domain is empty (i.e., l :?). Note that in Figure 8, in the interpretation of mkRect, the point arguments are put directly into the abstract value of the rectangle, producing indirect aliasing. The operations botLeft and topRight also produce aliasing. Auxiliary functions on Algebras As with signatures, algebras are manipulated in the semantics of , so we need various auxiliary functions on them. Let Alg( ) denote the class of all -algebras. Alg( ) def = fA jA is a -algebrag (7) For an algebra A, denote the components of the algebra by SORTSA, ObjectTypesA, etc. Also the following functions are de ned to produce a new algebra with the given component changed, for each component. The function setSORTS is shown below as an example; and the rest are entirely analogous. setSORTS : PowerSet(Type-name)! Alg( : SIGS)! Alg( ) setSORTS SORTS A = (SORTS;ObjectTypesA;LOCSA;VALSA;TtoSA;OPSA; externValA) Because operation interpretations are polymorphic, we need a notation for de ning the action of a polymorphic function on tuples of a given type. For this we use the notation [~ S 7! f ]gA, which is de ned by the following. ([~ S 7! f ]gA) def = (~v; ) : if ~v 2 VALSA~ S then f(~v; ) else gA(~v; ) (8) We also use the following to add an interpretation of an operation for tuples of arguments of type ~ S to OPSA. addOp [~ S][T ] : ( : SIGS)! (A : Alg( ))! Identi er ! ((VALSA~ S STORE [A])! (VALSAT STORE [A])?)! Alg( )? addOp [~ S][T ] (TYPES;OPS ;ResType) A [[g]] f = let i = length ~ S in if g 62 OPS i then ? else setOPS ([i 7! (OPSAi n fgAg) [ f[~ S 7! f ]gAg]OPSA) A To handle the hiding of the operation interpretations for operations named \creator(T)", \setter(I)", or \getter(I)", we adapt the notion of a reduct of an algebra (see, for example, [14, Section 6.8]) to this setting. Since we will only be using reducts to hide such operations, we only de ne Aj(hideInternalMessages ) for a -algebra A. Let OPS and OPS 0 be the operation symbols of and (hideInternalMessages ), respectively. Since we are deleting only the specially named operations, it su ces to de ne Aj(hideInternalMessages ) as being the same as A, except that for each g 2 (OPS n OPS 0), for each ~v and , gAj(hideInternalMessages )(~v; ) = ?. 14 Operation Interpretations that are not also in A mkPointD((v1; v2); ) def = alloc[Point]((v1; v2); ) abscissaD((l); ) def = let (v1; v2) = ( l) in (v1; ) ordinateD((l); ) def = let (v1; v2) = ( l) in (v2; ) addXD((lPoint; vInt); ) def = let (v1; v2) = ( lPoint) in ( ; [lPoint 7! (v1 + vInt; v2)] ) addYD((lPoint; vInt); ) def = let (v1; v2) = ( lPoint) in ( ; [lPoint 7! (v1; v2 + vInt)] ) upRightOfD((lPoint 1 ; lPoint 2 ); ) def = let (v11; v12) = ( lPoint 1 ) in let (v21; v22) = ( lPoint 2 ) in (v11 v21 ^ v12 v22; ) pointEqualD((lPoint 1 ; lPoint 2 ); ) def = let (v11; v12) = ( lPoint 1 ) in let (v21; v22) = ( lPoint 2 ) in (v11 = v21 ^ v12 = v22; ) mkRectD((l1; l2); ) def = let (lr; 0) = alloc[Rect]((l1; l2); ) in let (vb; 00) = upRightOfD(l1; l2) in if externValDBool(vb; 00) then (lr; 00) else (lr; [lr 7! (l2; l1)] 00) botLeftD((l); ) def = let (l1; l2) = ( l) in (l1; ) topRightD((l); ) def = let (l1; l2) = ( l) in (l2; ) horizMoveD((lRect; vInt); ) def = let (lbl; ltr) = ( lRect) in let (v0; 0) = addXD((lbl; vInt); ) in let (v00; 00) = addXD((ltr; vInt); 0) in ( ; 00) vertMoveD((lRect; vInt); ) def = let (lbl; ltr) = ( lRect) in let (v0; 0) = addYD((lbl; vInt); ) in let (v00; 00) = addYD((ltr; vInt); 0) in ( ; 00) Figure 8: The D-algebra D (part 2). 15 2.2.4 Other Semantic Domains Environments and States The state of a program is given by two mappings: an environment and a store. The type of stores is given in Equation (5) above. An environment maps identi ers to abstract values (which are thus the \denotable values"). The notation indicates that a state is a state over a particular algebra, as is an environment. ENV [A] def = Identi er n ! VALSA (9) STATE[A] def = ENV [A] STORE [A] (10) Like stores, environments are typed mappings. That is, if : ENV [A] and if x : T 2 dom( ), then (x) 2 VALSAT . We write emptyEnviron for the empty nite function from identi ers to denotable values, and de ne the following functions on environments, for any -algebra A [71]. emptyEnviron : ENV [A] = I :? overlay : ENV [A] ENV [A]! ENV [A] overlay( 1; 2) = I : if I 2 dom( 1) then 1[[I ]] else 2[[I ]] bind : Identi er VALSA ! ENV [A] bind(I; v) = I 0 : if I 0 = I then v else ? We also use the notation [I 7! v] as a shorthand for overlay(bind(I; v); ). Observations and Answers Recall that the second declaration, D2, of the main procedure in a program declares names for \outputs", each of which must have type Bool or Int. The denotation of the second part of the main procedure is a function from an algebra to an observation, which is itself a function from a state (de ned, for example, by the rst part of the main procedure) to a representation of this output. The output itself, the domain ANSWERS , is modeled as a nite function from the identi ers declared in the nal declaration to their corresponding external values. One can think of the program as printing these values (labeled by each identi er's name). OBSERVATION [A] def = STATE[A]! ANSWERS? (11) ANSWERS def = Identi er n ! EXTERNALS (12) Lists and Tuples For lists and tuples we follow the notation in [57]. For tuples, we use the usual pairing notation, and indicate indexing with a downward arrow; for example, (x; y) # 2 = y. As usual, tuples are written with vector notation, ~v. Recall that the notation D means all nite tuples of D. We use the notation [i 7! y]~v for the tuple such that ([i 7! y]~v) # i = y and for j 6= i, ([i 7! y]~v) # j = ~v # j. For lists, List(D) is the notation for the domain of lists of D, and we use the constant nil , and auxiliary functions cons, hd , and tl and the predicate null . To aid the reader, we use notations like x̂ for lists. We also assume an auxiliary function length, that gives the length of a list. We use a map functional as in SML [50], as well as a foldright functional, which is de ned below as the xedpoint of a generator. (For simplicity of notation, we use the convention that the application of a function of a type such as S T ! T? to ? produces ?.) foldright : 8S:8T:(S T ! T?)! T ! List(S)! T? 16 foldright = x G : f : b : x̂ : if null x̂ then b else f((hd x̂); G f b (tl x̂)) The auxiliary function \productize" converts a list of n items into an n-tuple, preserving the ordering. The auxiliary function \addToEnd" adds an item to the end of a list. These satisfy the following property for all 1 i length(v̂) + 1. productize (addToEnd v̂ v0) # i (13) = if i = (length(v̂) + 1) then v0 else (productize(v̂) # i) We also use the auxiliary function indexOf to nd the 1-based index of an element in a list. indexOf : 8T:T ! List(T )! Nat? indexOf = x G : x : x̂ : if null x̂ then ? else if (x = hd x̂) then 1 else 1 + (G x (tl x̂)) 2.3 Valuation Functions 2.3.1 Programs The denotation of a program re ects the split in the main procedure and in the semantics. It returns a signature, 00, a 00-algebra, A00, a state over that algebra (de ned by the rst part of the main procedure, \D1; C1"), and a function from 00-algebras to observations. The signature and algebra are obtained by elaborating the program's type and method declarations, and then hiding the primitive operations used to create objects and access elds of objects. The denotation of the main procedure is obtained by using the restricted algebra and signature, which ensures that the code in the main procedure cannot (successfully) use the primitives on objects, but must use the methods de ned in the method declarations. Therefore nothing in the main procedure can depend on these primitives. This also means that the signature and algebra returned do not re ect these details of the representation of objects used in this semantics. Some remarks about the notation used below are also in order. The type of P is a dependent type [11] [58, Chapter 8]; for example, the signature of the algebra returned is the same as the signature returned. Recall that the signature and the -algebra A used below are de ned in Figures 4 and 6. The valuation functions for type declarations, T D, and method declarations, MD, are de ned below. The valuation function for the main procedure, M, also de ned below, has a currying that re ects: the possibility of using the signature to do static checking on the syntax (for example, type checking), and the lack of dependence of the denotation produced on the particular algebra. Recall that the primitive operation symbols for creating objects, and for accessing their elds, are taken out of the signature by auxiliary function hideInternalMessages , which is de ned above in the auxiliary functions for signatures. The notation A0j(hideInternalMessages 0) is the reduct of A0 without these primitives; this notation is de ned above in the auxiliary functions for algebras. As a simpli cation in the semantics, we use ? both for nontermination and for any error condition. As in [57], we use a strict let construct; for example, the value of let x = ? in 3 is ?. P : Program! (( 00 : SIGS) (A00 : Alg( 00)) STATE[A00] ((B : Alg( 00))! OBSERVATION [B]))? P [[TD MD M]] = let ( ;A) = T D[[TD]] A in 17 let ( 0;A0) =MD[[MD]] A in let ( 00;A00) = (hideInternalMessages 0; A0j(hideInternalMessages 0)) in let (s1; f) =M 00 [[M]] A00 in ( 00;A00; s1; f) As noted earlier, the \output" of a program can be recovered from the information in the denotation of the program. One can use the following auxiliary function to do that. run : Program! ANSWERS? run [[P]] = let ( 00;A00; s1; f) = P [[P]] in f A00 s1 2.3.2 Type Declarations The elaboration of a type declaration produces an \updated" signature and algebra. It adds messages to the signature, and operations to the algebra, for creating objects of the type, and getting and setting their elds. Such messages are used by the denotational semantics only; to prevent their being used by programs, we give them names that are not nameable by programmers. The method for creating objects of a type T is named \creator(T )", and the methods for getting and setting a eld named I are named \getter(I)" and \setter(I)" respectively. Note also that types cannot be recursive as the formal list that is elaborated with a signature does not contain an object of the same type. The lack of recursive types is a simpli cation; to allow recursive types we would either have to add built-in support for variant representations (tagged unions) or mutually recursive type declarations, and also use a x-point construction for constructing the carrier sets. In the de nition below, F is the semantic function for formal lists (given below), the addType function is from the auxiliary functions for signatures, and the other auxiliary functions are described below. T D : Type-Declaration! ( : SIGS)! Alg( )! (( 0 : SIGS) Alg( 0))? T D[[]] A = ( ;A) T D[[type I fields (F̂)]] A = let F̂ 0 = F [[F̂]] in let 0 = addMessagesForTypeDecl[[I]] F̂ 0 (addType[[I]] ) in ( 0; compileTypeDecl 0 [[I]] F̂ 0 A) T D[[TD1 ; TD2]] A = let ( 0;A0) = T D[[TD1]] A in T D[[TD2]] 0 A0 Auxiliary functions used to update the signature There are two sets of auxiliary functions used in the elaboration of type declarations. The rst set of auxiliary functions is for adding messages to the signature. The function addMessagesForTypeDecl adds the creator message, and the messages to get and set each eld, to the signature. addMessagesForTypeDecl : Identi er ! List(Identi er Type-Name)! SIGS ! SIGS? addMessagesForTypeDecl[[I]] F̂ = addGetsAndSets[[I]] F̂ (addMessage[[creator(I)]] (formalTypes F̂ ) [[I]] ) The function formalTypes extracts the types from the denotation of a formal list. formalTypes : List(Identi er Type-Name)! List(Type-Name) 18 formalTypes F̂ = map ( (I; T ) : T ) F̂ The function addGetsAndSets adds messages to get and set each eld to the signature. Recall that \getter(I0)" and \setter(I0)" are just special names that are not nameable by programmers. addGetsAndSets : Identi er ! List(Identi er Type-Name)! SIGS ! SIGS? addGetsAndSets[[I]] F̂ = (foldright ( ((I0; T0); 0) : (addMessage[[getter(I0)]] ([[I]]) [[T0]] (addMessage[[setter(I0)]] ([[I]]; [[T0]]) [[Void]] 0))) ̂F ) Auxiliary functions used to update the algebra The second set of auxiliary functions is used to produce the new algebra with the methods for creating objects of the type, and accessing their elds. Aside from making up the methods, the work is done in compileTypeDecl itself. It uses formalTypes from above, the set. . . auxiliary functions on algebras de ned above, and the functions addGetAndSetOps and addCreatorOp de ned just below. For each type, the values of the type are locations, which the store maps to tuples of values of the elds (in the order in which they were declared). Each user-de ned type is thus represented as an object type, and its objects are locations and thus potentially mutable. The domain of abstract values for the type (V below) is a tuple of the values of the elds of the object. Recall that \sortFor(I)" is just a way of forming a sort name from a type name. compileTypeDecl : ( : SIGS)! Identi er ! List(Identi er Type-Name) ! Alg( )! Alg( )? compileTypeDecl [[I]] F̂ A = let ~ T = productize (formalTypes F̂ ) in let L = flI i j i 2 Natg in let V = VALSA~ T in let A0 = (setTtoS ([I 7! sortFor(I)]TtoSA) (setVALS ([sortFor(I) 7! V ]([I 7! L]VALSA)) (setLOCS ([I 7! L]LOCSA) (setObjectTypes (fIg [ObjectTypesA) (setSORTS (fsortFor(I)g [ SORTSA) A))))) in addGetAndSetOps [[I]] F̂ (addCreatorOp [[I]] ~ T A) The auxiliary function addGetAndSetOps uses the addOp auxiliary function de ned for algebras to add each get and set operation. The operation interpretations (methods) themselves are created by passing appropriate parameters to the auxiliary functions fetch and set . addGetAndSetOps : ( : SIGS)! Identi er ! List(Identi er Type-Name) ! Alg( )! Alg( )? addGetAndSetOps [[I]] F̂ A = (foldright 19 ( ((I0; T0);A0) : let A00 = addOp[(I)][T0] A0 [[getter(I0)]] (fetch[I][T0] [[I0]] F̂ ) in addOp [(I; T0)][Void] A00 [[setter(I0)]] (set [I][T0] [[I0]] F̂ )) ÂF ) The elds of an object are tuples of values, stored in the order in which the elds are declared. The denotation of the eld declarations is used by the auxiliary function on lists, indexOf, to obtain the index into the tuple. Both fetch and set return a function which can be used in an algebra to interpret a method. The function produced by set updates the store, and returns nothing. Returning nothing is denoted by returning *, which the reader will recall is the only abstract value of the type Void in A (Figure 6). It is ne to assume that the algebra in question is based on A , because set is only used in giving denotations to methods, and so is not involved in giving the denotation of the main procedure. Alternatively, we could have written \nothingA((); [l 7! ~v] )" below instead of \( ; [l 7! ~v] )", which is equivalent (because A must be based on A in this context). fetch [T ][T 0] : Identi er ! List(Identi er Type-Name) ! VALSAT STORE [A]! (VALSAT 0 STORE [A])? fetch [T ][T 0] [[I]] F̂ = (l; ) : if (l 62 LOCSAT ) then ? else let i = indexOf (I; T 0) F̂ in (( l) # i; ) set [T ][T 0] : Identi er ! List(Identi er Type-Name) ! (VALSAT VALSAT 0) STORE [A]! (VALSAT 0 STORE [A])? set [T ][T 0] [[I]] F̂ = ((l; v); ) : if (l 62 LOCSAT ) then ? else let i = indexOf (I; T 0) F̂ in let ~v0 = [i 7! v]( l) in ( ; [l 7! ~v0] ) The function addCreatorOp adds an operation interpretation for the operation that creates an object. The operation interpretation, f below, uses the alloc function de ned above on stores to allocate a location of the type holding the tuple of arguments of the creator. addCreatorOp : ( : SIGS)! Identi er ! Type-Name ! Alg( )! Alg( )? addCreatorOp [[I ]] ~ T A = let f = ( (~v; ) : if ~v 62 VALSA~ T then ? else alloc[I](~v; )) in addOp[~ T ][I] A [[creator(I)]] f 2.3.3 Formal Lists, Formals, and Type Names The denotations of formal lists, formals, and type names are all relatively straightforward. The error checking they perform is encapsulated in T , which checks to be sure the type named is de ned in the signature. We assume that a Formal-List is actually a list. F : SIGS ! Formal-List! List(Identi er Type-Name)? F [[F̂ ]] = map (F ) [[F̂ ]] 20 F : SIGS ! Formal! (Identi er Type-Name)? F [[I : T]] = let T 0 = T [[T]] in (I; T 0) T : SIGS ! Type-Name! Identi er? T (TYPES ;OPS ;ResType) [[T ]] = if T 2 TYPES then T else ? 2.3.4 Method Declarations The valuation function for method declarations does not allow recursive methods, although this could be corrected by using a xed-point construction. It uses the semantic function for bodies, B, and an auxiliary function bindActuals , both of which are de ned below. MD : Method-Declaration! ( : SIGS)! Alg( )! (( 0 : SIGS) Alg( 0))? MD[[]] A = ( ;A) MD[[method I(F̂):T fBg]] A = let F̂ 0 = F [[F̂]] in let T 0 = T [[T]] in let f = ( (~v; ) :B [[B]] A (bindActuals[A] ~v F̂ 0; )) in let ~ S = productize (formalTypes F̂ 0) in let 0 = addMessage[[I]] ~ S T 0 in let A0 = addOp[~ S][T 0] 0 A [[I]] f in ( 0; A0) MD[[MD1 ; MD2]] A = let ( 0;A0) =MD[[MD1]] A in MD[[MD2]] 0 A0 The binding of actuals to formals creates an environment. The folding process in the call to foldright passes the -abstraction an element of F̂ , which is a pair of an identi er and a type name, the forming environment, and the index of the element of the list F̂ ; hence the notation (Ii; Si) used below is accurate. bindActuals[A] : (VALSA) ! List(Identi er Type-Name)! ENV [A]? bindActuals[A] ~v F̂ = let ~ S = productize (formalTypes F̂ ) in if ~v 62 VALSA~ S then ? else let ( 0; n) = (foldright ( ((Ii; Si); ( ; i)) : ([Ii 7! (~v # i)] ; i 1)) (emptyEnviron; length F̂ ) F̂ ) in 0 2.3.5 Bodies The denotation of a method body could also be used for the bodies of procedures or local blocks, if had procedures or local blocks. As such it is written in the tradition of denotational semantics, and relies on an algebra to do its work, and does not change the algebra. B : ( : SIGS)! Body! (A : Alg( ))! STATE[A]! (VALSA STORE [A])? 21 B [[D C ; return E]] A s = let ( 1; 1) = D [[D]] A s in let 2 = C [[C]] A ( 1; 1) in E [[E]] A ( 1; 2) 2.3.6 Declarations of Constants A constant declaration evaluates its expression, and returns a new state with a binding of the declared identi er to the expression's value. The signature is used to check that the type has been declared. D : ( : SIGS)! Declaration! (A : Alg( ))! STATE[A]! STATE[A]? D [[]] A s = s D [[const I:T = E]] A ( ; ) = let T 0 = T [[T]] in let (v; 0) = E [[E]] A ( ; ) in if v 62 VALSAT 0 then ? else ([I 7! v] ; 0) D [[D1 ; D2]] A s = D [[D2]] A (D [[D1]] A s) 2.3.7 Expressions, Expression Lists The meaning of an expression is found by either looking up an identi er in the environment, or by using the algebra and store to evaluate an operation. The semantic function for numerals, N , has the following type. N : ( : SIGS)! Numeral! (A : Alg( ))! STORE [A]! (VALSAInt STORE [A])?. The store is needed by algebras that represent integers using locations, as the denotations for numerals should be independent of the algebra. The details of N are left an exercise for the reader. The denotations for true, false, and nothing use the appropriate method in the algebra; hence these semantic equations are also independent of the particular algebra. Similarly, the meaning of a method call uses an operation in an algebra. While object creation and eld access use operations in the algebra also, these are the specially named operations \creator(T)" and \getter(I)" that are speci c to this semantics; hence calls to these special operations re ect a dependence of those expressions on the algebra. This is why such expressions are not allowed in the main procedure. E : ( : SIGS)! Expression! (A : Alg( ))! STATE[A]! (VALSA STORE [A])? E [[I]] A ( ; ) = (let v = [[I]] in (v; )) E [[N]] A ( ; ) = N [[N]] A E [[true]] A ( ; ) = trueA((); ) E [[false]] A ( ; ) = falseA((); ) E [[nothing]] A ( ; ) = nothingA((); ) E [[g(Ê)]] A ( ; ) = let (v̂; 0) = E [[Ê]] A ( ; ) in gA(productize v̂; 0) E [[new T(Ê)]] A ( ; ) = let T 0 = T [[T]] in let (v̂; 0) = E [[Ê]] A ( ; ) in creator(T 0)A(productize v̂; 0) E [[I1 . I2]] A ( ; ) = 22 let (v; 0) = E [[I1]] A ( ; ) in getter(I2)A(v; 0) The meaning of a list of expressions is a list of values together with the store that results from their evaluation. The expressions are evaluated left to right. E : ( : SIGS)! Expression-List ! (A : Alg( ))! STATE[A] ! (List(VALSA) STORE [A])? E [[]] A ( ; ) = (nil ; ) E [[Ê En]] A ( ; ) = let (v̂; 0) = E [[Ê]] A ( ; ) in let (vn; n) = E [[En]] A ( ; 0) in ((addToEnd v̂ vn); n) 2.3.8 Commands The semantic functions for commands are fairly straight-forward. Note, however that the denotation of the eld update command depends on the special operation \setter(I)", and thus is speci c to this semantics. Hence the eld update command is not allowed in the main procedure. On the other hand, in an if-command, the external value of the test is used, which makes the semantics for if independent of the algebra. C : ( : SIGS)! Command! (A : Alg( ))! STATE[A]! STORE [A]? C [[E]] A ( ; ) = let (v; 0) = E [[E]] A ( ; ) in 0 C [[I1.I2 := E]] A ( ; ) = let (v0; 0) = E [[E]] A ( ; ) in let (v1; 1) = E [[I1]] A ( ; 0) in let (v ; 2) = setter(I2)A((v1; v0); 1) in 2 C [[C1; C2]] A ( ; ) = let 1 = C [[C1]] A ( ; ) in C [[C2]] A ( ; 1) C [[if E1 then C1 else C2 fi]] A ( ; ) = let (v; 0) = E [[E1]] A ( ; ) in if externValABool(v; 0) then (C [[C1]] A ( ; 0)) else (C [[C2]] A ( ; 0)) 2.3.9 Main Procedure The meaning of the main procedure is a pair of a state and a function from algebras to observations. The state returned, ( ; 0), is produced by the rst part of the main procedure, D1 and C1. The function from algebras to observations is de ned by the second part of the main procedure, C2 and D2; this function takes an algebra, B, and a state over B, and, starting from the given state, computes a nal state, and returns a nite function. The nite function is de ned on the names declared in D2, and for each such name gives its external value in the nal state. The auxiliary function typeEnvAndCheckVisible, de ned below, checks that all the declarations in D2 are declarations of constants of visible type, and if so returns a type environment. This type environment is a nite function from identi ers to their types. Since the domain of this nite function, H , is just the names in D2, this ensures that only those names are \output" by the program. (The domain OBSERVATION [B] is de ned in Section 2.2.4 above.) M : ( : SIGS)! Program! (A : Alg( ))23 ! (STATE[A] (B : Alg( )! OBSERVATION [B]))? M [[ main fobserve D1 C1 by C2 D2g]] A = let ( ; ) = D [[D1]] A (emptyEnviron; emptyStore) in let 0 = C [[C1]] A ( ; ) in let H = typeEnvAndCheckVisible[[D2]] in let f = ( B : ( B; B) : let 0 B = C [[C2]] B ( B; B) in let 00 B; 00 B = D [[D2]] B ( B; 0 B) in [[I ]] : let T = H [[I ]] in externValBT ( 00 B[[I ]]; 00 B)) in (( ; 0); f) The following auxiliary function returns checks declarations to see that they are declaring constants of types Bool or Int, and returns a nite function from the names declared to their types. Since this kind of nite function is a \type environment" (as opposed to a value environment), we use the auxiliary functions on environments de ned above (and ask the reader's pardon for not rede ning them with new types). typeEnvAndCheckVisible : Declaration! (Identi er n ! VIS)? typeEnvAndCheckVisible[[]] = emptyEnviron typeEnvAndCheckVisible[[const I:T = E]] = if T 62 VIS then ? else bind(I;T) typeEnvAndCheckVisible[[D1 ; D2]] = overlay(typeEnvAndCheckVisible[[D2]]; typeEnvAndCheckVisible[[D1]]) 2.4 Discussion In this section we give an example of the semantics, and discuss some issues relating to our semantics of and our semantic technique. First we bring together the pieces of our running example, the program in Figure 2. The denotation of this program is a four-tuple. Recall that the rst element of this tuple is the signature, D, which was shown in Figure 5, and that the second element is the algebra, D, which was shown in Figures 7 and 8. The third element is a state over D, and the fourth is a function from states over D-algebras to observations. The state is ( D; D), where the environment D satis es: D(w) = lRect 3 D(x) = lRect 4 D(y) = lRect 4 D(z) = lPoint 0 and the store, D satis es: D(lRect 3 ) = (lPoint 1 ; lPoint 2 ) D(lRect 4 ) = (lPoint 1 ; lPoint 0 ) D(lPoint 0 ) = (2; 5) D(lPoint 2 ) = (3; 4) D(lPoint 1 ) = (1; 1): This state is pictured in Figure 9. The function, fobs , that is the fourth element of the denotation of the program in Figure 2 is given in Figure 10. 24 * 3 ZZZZZ~ HHHHHHHHHHj AAAAAAU l3:Rect l4:Rect l0:Point l2:Point l1:Point z:Point y:Rect x:Rect w:Rect ) , ( ) , ( ) , ( ( , ) ) , ( 1 1 3 4 2 5 Figure 9: Picture of the state ( D; D) over the algebra D. 25 fobs = let H = [[I ]] : if I 2 fshouldBe1; shouldBe5; shouldBe4g then Int else ? in ( B : ( ; 0) : let vy = y in let (vtr(y); 1) = topRightB((vy); 0) in let (v2; 0 1) = N [[2]] B 1 in let (v5; 00 1) = N [[5]] B 0 1 in let (vp; 2) = mkPointB((v2; v5); 00 1) in let (vb; 3) = pointEqualB((vtr(y); vp); 2) in let 5 = if externValBBool(vb; 3) then let vw = w in let v1 = N [[1]] B in let (vax; 4) = addXB((vw; v1); 3) in 4 else let (v ; 4) = nothingB((); 3) in 4 let (vbl(y); 6) = botLeftB((vy); 5) in let (va(bl(y)); 7) = abscissaB((vbl(y)); 6) in let 7 = [shouldBe1 7! va(bl(y))] in let vz = 7 z in let (vo(z); 8) = ordinateB((vz); 7) in let 8 = [shouldBe5 7! vo(z)] 7 in let vw = 8 w in let (vtr(w); 9) = topRightB((vw); 8) in let (va(tr(w)); 10) = abscissaB((vtr(w)); 9) in let 10 = [shouldBe4 7! va(tr(w))] 8 in [[I ]] : let T = H [[I ]] in externValBT ( 10[[I ]]; 10) Figure 10: The function, fobs , that is produced as the fourth element of the semantics of the example program. Note that 5 is the store after executing the if-command following the by in the example program, and ( 10; 10) is the state after elaborating the declarations at the end of the program. 26 The above semantics may seem complex, and there is certainly more notation than in a traditional denotational semantics. Clearly the algebraic structures are also more complex than is traditional in the study of, for example, equational speci cation. Some of the notational complexities arise from our penchant for multi-sorted algebras and fairly exact types. But the majority come from the split in the semantics. First, we split the usual environment in two | the two pieces being the algebra (which can be thought of as an environment for methods, as it gives an interpretation to each operation symbol) and the usual (value) environment. We also split the domains in two { the two pieces being the carrier sets of the algebra and the usual domains for expressions, answers, etc. (which are not much in evidence in such a simple language). The notation is also made more complex by our passing the signature around explicitly, as a thing to be manipulated by the semantics; this could be easily xed by writing the signature as a subscript, as in \C [[C1;C2]] A s", but the signature is explicitly manipulated by the semantic functions for programs, type declarations, and method declarations, so we prefer the notation used in the paper. What justi es this notational complexity, the split semantics, and ultimately any semantic description technique1, is its usefulness in furthering the study of programming languages. We o er an example of the utility of the technique in the next section, where we study implementation concepts for ADTs. The main advantage of this framework is that one can study the semantics of either half of the semantics somewhat separately. Although we have not done so, studying ways to give semantics to type and method declarations, or other languages for specifying such algebras might be fruitful. One could, for example, de ne the algebras not by programming, but by some speci cation method [18] or logic programming technique. Note especially that in Figure 8, we have given what amounts to an equational presentation of an algebra with mutable objects. The kind of mutation allowed is not just one-level mutation either; that is, it is not just variables containing pure values. Because of the store, one can have interesting aliasing relationships. Thus we believe the conventional view that equational speci cations are not suitable for studying mutation might need revision. This idea is, of course, inspired by denotational semantics and functional programming ideas. However, we are not aware of any work studying equational speci cations of mutable types which uses it. (Relationships with related work we do know about is discussed in Section 4 below.) Our main interest, however, is in studying the denotational half of the semantics | the semantics of expressions, commands, etc. We are especially interested in studying behavioral properties of algebraic models with mutable types in the context of objectoriented programming. In such studies we often de ne languages that compute over models of ADTs, allowing us to start with the algebraic structures and compare their properties (for example, [30]). A small example of such a study appears in the next section. However, we hasten to point out that others are also interested in questions of behavioral properties of programs. For example, full abstraction is such a question. Recent work on full abstraction has focused on the semantics of blocks and local variables. The work of O'Hearn and Tennent [47] [48] [65] and the work of Sieber [62] [63] [61] use logical relations (i.e., higher-order extensions of the kind of simulation relations we study in the next section), to obtain a restricted domain of procedure denotations. The idea is to restrict the domain of procedure denotations so that a procedure can only a ect certain variables, not the entire store [39]. Reddy has investigated another approach to the full abstraction problem for local variables that uses techniques akin to object-oriented programming to prevent unwanted 1Yuri Gurevich, personal communication, March 1994. 27 modi cations to the store [52]. We speculate that it might be possible to characterize, perhaps algebraically, varieties of algebras that have behavior that is appropriate, and that this might be of some interest in the study of full abstraction for programming languages with local variables. More probably, such a split semantics will be of use for studies of full abstraction for programming languages with ADT constructs and for object-oriented languages. Granting the potential interest in our semantic description technique, the next logical question to ask is whether it has intrinsic limitations compared to standard ways of doing denotational semantics. We leave the detailed study of such questions for future work, but brie y raise some obvious issues. The rst issue is whether some of the features we left out of are intrinsically beyond our techniques. While not exhausting this question by any means, we discuss two such extensions here: procedures and block structure. We believe that it would be possible to add procedure declarations to the language with little conceptual di culty. One simply has to pass a separate environment for procedures, or modify the domain of environments by introducing a domain of denotable values, one of whose summands would be a domain for procedures. Indeed, we have worked out such an extension, and it is interesting to note that the domain for (call-by-value) procedures (that return a result) would be something like the following. Procedure[ ] = (A : Alg( ))! (VALSA STORE [A])! (VALSA STORE [A])? This emphasizes that such procedures would take an algebra (of the appropriate signature) as an argument, and compute over it. Such a domain would also serve for rst-class procedures (call-by-value -expressions), except that instead of passing and returning only values from the algebra, one would pass and return denotable values, which would include such procedures as a summand. Alternatively, one could model rst-class procedures as objects, and give them types and values in the algebra. (This would more closely correspond to Smalltalk [19].) We leave it as future work to work out the details of such approaches. Recursive procedures seem to pose no particular di culties; and we leave as future work the working out of the appropriate domain theory for constructing algebras with recursive methods and recursive data. Work on continuous algebras may be of use in solving such problems [16] [70] [20] [43] [74, Section 3.3.3]. Another feature not in is block structure, more speci cally local declarations of types and methods. The semantics could be modi ed to allow the declaration of types and methods in local blocks without conceptual di culties; however, in doing so it is more di cult to see the separation between the two halves of the semantics, as they would both be present in each block in the same way they are present in as a whole. 3 Simulation Relations As an example of the utility of our split semantics, we o er the following simple study of simulation between states over algebraic models. In this study we ignore type and method declarations, and focus on the behavior of their denotations, as observed by commands and declarations in the main procedure. Since we will be ignoring the details of type and method declarations, in what follows, let = (TYPES ;OPS;ResType) stand for an arbitrary signature. The simulation relations we study help one decide when one ADT behaves like another [59] [46] [28] [31]. This is useful in theoretical contexts [42]; also the general idea of 28 simulation and re nement of ADTs is important for optimization. If the abstraction of a faster implementation simulates a slower one's behavior, then one can replace the slower implementation by the faster implementation. To de ne simulation relations appropriate for and its semantics, one might think that the appropriate notion would simply relate abstract values. However, that would not take locations, and hence aliasing, into account. Neither can one simply relate locations, since one must take the abstract values stored in the locations into account if the relationships are to preserve observable behavior. Even relating locations together with stores is not enough, since that would not take aliasing among identi ers into account. So the formulation of simulation relations we present relates states over one algebra to states over another algebra. (In this respect it is similar to the base case of the logical relations used, for example, in [47] [48] [65]. They are extensions of the relations used in [33].) De nition 3.1 (simulation relation) Let C and A be -algebras. A -simulation relation R from C to A is a binary relation on states R STATE[C]? STATE[A]? such that for each ( C; C) 2 STATE[C] and for each ( A; A) 2 STATE[A], the following properties hold: well-formed: ( C; C)R ( A; A)) (dom C) (dom A), bindable: for each type T , for each identi er x : T , and for each identi er y : T 2 (dom C), ( C; C)R ( A; A)) ([x 7! ( C y)] C; C)R ([x 7! ( A y)] A; A); (14) bistrict: ?R?, and whenever sR s0 and either s or s0 is ?, then so is the other, substitution: for each tuple of types ~ S, for each type T , for each operation symbol g : ~ S ! T , for each tuple of identi ers ~x : ~ S 2 (dom C), and for each identi er y : T , ( C; C)R ( A; A)) (let (rC; 0 C) = gC(( C ~x); C) in ([y 7! rC] C; 0 C)) R (15) (let (rA; 0 A) = gA(( A ~x); A) in ([y 7! rA] A; 0 A)); shrinkable: if ( 0 C; 0 C) ( C; C), and ( 0 A; 0 A) ( A; A), and (dom 0 C) (dom 0 A), then ( C; C)R ( A; A)) ( 0 C; 0 C)R ( 0 A; 0 A), EXTERNALS-identical: for each type T 2 VIS, for each identi er x : T 2 (dom C), if ( C; C)R ( A; A), then externValC(( C x); C) = externValA(( A x); A): In the substitution property, ~x : ~ S 2 (dom C), means that for each i, xi : Si 2 (dom C), and ( C ~x) means the tuple of ( C xi). The tuples ~ S and ~x : ~ S can be empty. The EXTERNALS-identical property ensures that a simulation is the identity on external representations. In the shrinkable property, ( 0 C; 0 C) ( C; C) means that for all types T , and for all identi ers x : T , x : T 2 (dom 0 C) ) ( 0 C x) = ( C x) and for all locations l : T , l : T 2 (dom 0 C)) ( 0 C l) = ( C l). 29 3.1 Examples of Simulation Relations As a trivial example, the identity relation on STATE[D]? STATE[D]? is a D-simulation relation from our example algebra D to itself. To build a more interesting example, we give a di erent D-algebra, E, in Figures 12 and 13. This algebra is built on a di erent -algebra, B given in Figure 11. These algebras use objects for the booleans and integers. In this sense they represent what a \pure object-oriented" semantics might produce, and thus would be more faithful models of languages like Smalltalk, where everything is (at least conceptually) an object. An example of a state over E that we would relate to our example state ( D; D) is the state ( E; E), where E is such that ( E w) = lRect 10 ( E x) = lRect 9 ( E y) = lRect 9 ( E z) = lPoint 8 and E is de ned as follows. ( E lRect 10 ) = (lPoint 6 ; lPoint 7 ) ( E lRect 9 ) = (lPoint 6 ; lPoint 8 ) ( E lPoint 8 ) = (lInt 2 ; lInt 5 ) ( E lPoint 7 ) = (lInt 3 ; lInt 4 ) ( E lPoint 6 ) = (lInt 1 ; lInt 1 ) ( E lInt 5 ) = 5 ( E lInt 4 ) = 4 ( E lInt 3 ) = 3 ( E lInt 2 ) = 2 ( E lInt 1 ) = 1 A picture of this state is given in Figure 14. We now give an example of a simulation relation between states of E and states of D that would relate, for example, ( E; E) to ( D; D). We consider rst a formalization of the notion of similarity of abstract values of two locations and then augment that with some conditions that ensure well-formedness and that only states with the same aliasing are related. Given two stores over E and D, the function S 0 : (STORE [E] STORE [D])! ((VALSE VALSD)! Boolean) returns a predicate that tests two values for having the same abstract value in the corresponding stores. It is de ned inductively by requiring locations of the immutable types to have equal abstract values and by requiring Point and Rect locations to have related abstract values in each component: basis: For each type T 2 fBool; Intg, for each pair of stores ( E; D), for each vE 2 VALSET and vD 2 VALSDT : S 0 T ( E; D)(vE; vD) def = (externValET (vE; E) = externValDT (vD; D)): (16) For clarity, we emphasize that we are using a nonstrict interpretation of equality in which, for example, ? = 3 is false. Therefore, if externValET (vE; E) is ? and if externValDT (vD; D) is proper, then the result of S 0 T ( E; D)(vE; vD) is false. 30 SORTSB def = TYPES [ fsortFor(Bool); sortFor(Int)g ObjectTypesB def = fBool; Intg LOCSB T def = flT i j i 2 Natg; for each T 2 ObjectTypesB Type to Sort Mapping (TtoSB) Bool 7! sortFor(Bool) Int 7! sortFor(Int) VALSB Void def = f g VALSB sortFor(Bool) def = ftrue; falseg VALSB sortFor(Int) def = f0; 1; 1; 2; 2; . . .g and for T 2 ObjectTypesB , VALSB T def = LOCSB T externValB Bool(l; ) def = ( l) externValB Int(l; ) def = ( l) Operation Interpretations nothingB ((); ) def = ( ; ) trueB ((); ) def = alloc[Bool](true; ) falseB ((); ) def = alloc[Bool](false; ) andB ((l1; l2); ) def = alloc[Bool](( l1) ^ ( l2); ) orB ((l1; l2); ) def = alloc[Bool](( l1) _ ( l2); ) notB ((l); ) def = alloc[Bool](:( l); ) 0B ((); ) def = alloc[Int](0; ) 1B ((); ) def = alloc[Int](1; ) addB ((l1; l2); ) def = alloc[Int](( l1) + ( l2); ) multB ((l1; l2); ) def = alloc[Int](( l1) ( l2); ) negateB ((l); ) def = alloc[Int]( ( l); ) equalB ((l1; l2); ) def = alloc[Bool](( l1) = ( l2); ) lessB ((l1; l2); ) def = alloc[Bool](( l1) < ( l2); ) leqB ((l1; l2); ) def = alloc[Bool](( l1) ( l2); ) Figure 11: The -algebra B . Recall that TYPES means the TYPES of . 31 SORTSE def = TYPES [ fsortFor(Int); sortFor(Bool); sortFor(Point); sortFor(Rect)g ObjectTypesE def = ObjectTypesB [ fPoint; Rectg LOCSET def = flT i j i 2 Natg; for each T 2 ObjectTypesE Type to Sort Mappings (TtoSE) added to TtoSB Point 7! sortFor(Point) Rect 7! sortFor(Rect) Abstract values added to VALSB VALSEsortFor(Point) def = f(lx; ly) j lx; ly 2 LOCSEIntg VALSEsortFor(Rect) def = f(lbl; ltr) j lbl; ltr 2 LOCSEPointg and for T 2 ObjectTypesE, VALSET def = LOCSET externValE def = externValB Figure 12: The D-algebra E (part 1). In this gure, TYPES is from D. 32 Operation Interpretations that are not also in B mkPointE((l1; l2); ) def = alloc[Point]((l1; l2); ) abscissaE((l); ) def = let (l1; l2) = ( l) in (l1; ) ordinateE((l); ) def = let (l1; l2) = ( l) in (l2; ) addXE((lPoint; lInt); ) def = let (l1; l2) = ( lPoint) in let (lnew ; 0) = addE((l1; lInt); ) in ( ; [lPoint 7! (lnew ; l2)] 0) addYE((lPoint; lInt); ) def = let (l1; l2) = ( lPoint) in let (lnew ; 0) = addE((l2; lInt); ) in ( ; [lPoint 7! (l1; lnew)] 0) upRightOfE((lPoint 1 ; lPoint 2 ); ) def = let (l11; l12) = ( lPoint 1 ) in let (l21; l22) = ( lPoint 2 ) in let (lb1; 0) = (leqB(l11; l21)) in let (lb2; 00) = (leqB(l12; l22)) in andB((lb1; lb2); 00) pointEqualE((lPoint 1 ; lPoint 2 ); ) def = let (l11; l12) = ( lPoint 1 ) in let (l21; l22) = ( lPoint 2 ) in let (lb1; 0) = (equalB(l11; l21)) in let (lb2; 0) = (equalB(l12; l22)) in andB((lb1; lb2); 00) mkRectE((l1; l2); ) def = let (lr; 0) = alloc[Rect]((l1; l2); ) in let (lb; 00) = upRightOfE(l1; l2) in if externValEBool(lb; 00) then (lr; 00) else (lr; [lr 7! (l2; l1)] 00) botLeftE((l); ) def = let (l1; l2) = ( l) in (l1; ) topRightE((l); ) def = let (l1; l2) = ( l) in (l2; ) horizMoveE((lRect; lInt); ) def = let (lbl; ltr) = ( lRect) in let (v0; 0) = addXE((lbl; lInt); ) in let (v00; 00) = addXE((ltr; lInt); 0) in ( ; 00) vertMoveE((lRect; lInt); ) def = let (lbl; ltr) = ( lRect) in let (v0; 0) = addYE((lbl; lInt); ) in let (v00; 00) = addYE((ltr; lInt); 0) in ( ; 00) Figure 13: The D-algebra E (part 2). 33 ? AAAAAAAAU ) , ( AAAAAAAAU ? ( , ) * 3 ZZZZZZ~ HHHHHHHHHHHHj AAAAAAAAU ? l10:Rect l9:Rect l8:Point l7:Point l6:Point z:Point y:Rect x:Rect w:Rect 4 5 2 3 ) , ( 1 ) , ( ) , ( Figure 14: Picture of the state ( E; E) over the algebra E. 34 For each pair of stores ( E; D), for each vE 2 VALSEVoid and vD 2 VALSDVoid: S 0 Void( E; D)(vE; vD) def = true (17) Point: For each pair of stores ( E; D) and locations (lE; lD) 2 (LOCSEPoint LOCSEPoint), S 0 Point( E; D)(lE; lD) def = 8>><>>: true ; if lE 62 dom( E) ^ lD 62 dom( D) false; if (lE 2 dom( E)) 6= (lD 2 dom( D)) b; if ( E lE) = (lx; ly), ( D lD) = (v0 x; v0 y), and b = (S 0 Int( E; D)(lx; v0 x)^ S 0 Int( E; D)(ly; v0 y)): (18) Rect: For each pair of stores ( E; D) and locations (lE; lD) 2 (LOCSERect LOCSERect), S 0 Rect( E; D)(l; l0) def = 8>><>>: true ; if lE 62 dom( E) ^ lD 62 dom( D) false; if (lE 2 dom( E)) 6= (lD 2 dom( D)) b; if ( E lE) = (lE;bl; lE;tr), ( D lD) = (lD;bl; lD;tr), and b = (S 0 Point( E; D)(lE;bl; lD;bl) ^ S 0 Point( E; D)(lE;tr; lD;tr)):(19) We can relate two states only if the aliasing present in the rst is mimicked in the second. To this end we introduce the aliasing graph of a state ( ; ) over a D-algebra. This directed graph has as its nodes: the identi ers in (dom ), the locations in (dom ) that have type Point or Rect. It has directed edges as follows: From an identi er x of type Point or Rect to a location l if ( x) = l. From a location l : Rect to locations l0; l00 : Point if (l0; l00) = ( l). We write AliasG( ; ) for this graph. As an example, the AliasG( D; D) is shown in Figure 15. It is also a picture of AliasG( E; E). We consider one aliasing graph to be mimicked in another if there is an injective graph homomorphism from the rst to the second. Recall that if (N1; E1) and (N2; E2) are pairs of node and edge sets representing two graphs, then f = (fn; fe) is a graph homomorphism if and only if (n; n0) 2 E1 ) (fe (n; n0)) = ((fn n); (fn n0)): (20) We now have enough machinery to de ne an interesting E-simulation relation from E to D, which we will call R0. De nition 3.2 (R0) The D-simulation relation R0 STATE[E]? STATE[D]? is dened such that ?R0? and ( 1; 1)R0( 2; 2) if and only if the following conditions all hold: (dom 1) (dom 2), for each type T , for each x : T 2 (dom 1), S 0 T ( 1; 2)(( 1 x); ( 2 x)) holds, so that the abstract values of x in both states are similar, and there is an injective graph homomorphism from AliasG( 1; 1) to AliasG( 2; 2) that is the identity on (dom 1). Requiring that there be an injective graph homomorphism ensures that aliasing for the mutable types Point and Rect is taken into account. Lemma 3.3 The relation R0 is a D-simulation relation from E to D. Proof Sketch: See Appendix A. 35 @@@R HHHHj * * S S S o w:Rect l:Rect l:Point l:Rect z:Point y:Rect x:Rect l:Point l:Point Figure 15: Aliasing graph for the states ( D; D) and ( E; E). 3.2 Simulation is Preserved in the Main Procedure In this section we show that simulation relations are preserved by the constructs of that can appear in the main procedure, and thus by observations written in . Since object creation expressions, eld access expressions, and eld update commands use primitives of the algebra that are speci c to the semantics given in Section 2, they cannot be applied to all algebras and cannot appear in the main procedure. To avoid constantly describing the expressions, commands, and declarations that can appear in the main procedure, we make the following de nition. De nition 3.4 (main procedure expression, command, declaration) In , an expression (command) is a main procedure expression (command) if and only if it satis es the grammar for E0 (C0) in Figure 16. A declaration of is a main procedure declaration if and only if it satis es the grammar for D0 in Figure 16 and in addition declares only constants of types Bool or Int. We also need a simple type system for . The type of a main procedure expression is based on the type information in the algebra's signature, and a type environment, writtenH , obtained from the constant declarations in the main procedure. The notation ;H ` E : T means E has type T in H ; in this case we say that E is well H-typed. A command is well H-typed if and only if each of its subexpressions is well H-typed. We use the notation ;H ` [[D]] =) H 0 to mean that D is well H-typed, and produces the type environment H 0 when elaborated. See Appendix B for details. We relate type environments to value environments in the following way. 36 Abstract Syntax of Main Procedure Expressions, Commands, Declarations: E0 2 Main-Proc-Expression E0* 2 Main-Proc-Expression-List C0 2 Main-Proc-Command D0 2 Main-Proc-Declaration E0 ::= I j N j true j false j nothing j g(E0*) E0* ::= j E0* E0 C0 ::= E0 j C01; C02 j if E01 then C01 else C02 fi D0 ::= j const I : T = E0 j D1 ; D2 Figure 16: Syntax of main procedure expressions, commands and declarations. All other syntax is as in the standard abstract syntax for . De nition 3.5 (H-environment, H-state) Let A be a -algebra and let H be a type environment. A value envionment, 2 ENV [A], is an H-environment if and only if for each I 2 dom(H), and for each type T , if H [[I ]] = T then [[I ]] 2 VALSAT . A state, ( ; ) is an H-state if and only if is an H-environment. The following lemma says that simulation relations are preserved by the evaluation of a main procedure expression in related states. Recall that we use let as a strict binding mechanism. Lemma 3.6 Let B and A be -algebras. Let R be a -simulation relation from B to A. Let H be a type environment. Then for all H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A] such that (dom B) (dom A), for each type T , for each main procedure expression E such that ;H ` E : T , for each identi er y : T , ( B; B)R ( A; A)) (let (vB; 0 B) = E [[E]] B ( B; B) in ([y 7! vB] B; 0 B)) R(let (vA; 0 A) = E [[E]] A ( A; A) in ([y 7! vA] A; 0 A)): Proof: (by induction on the structure of E). Let H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A] be given such that (dom B) (dom A). Let T and E be given such that ;H ` E : T . Let y : T be given. Suppose that ( B; B)R ( A; A). (basis) If E is an identi er I of type T , then the result follows from the assumption and the bindable property. If E is a numeral, N, or one of true, false, or nothing, then the result follows from the substitution property. (inductive step) Suppose that E has the form g(E*). Since g(E*) has type T , it must be that ;H ` E : ~ S and ResType(g; ~ S) = T , for some ~ S. The inductive hypothesis is that the lemma is true for each subexpression, Ei of type Si in the list E*. That is, 37Syntax of Main Procedure Expressions, Commands, Declarations: E0 2 Main-Proc-Expression E0* 2 Main-Proc-Expression-List C0 2 Main-Proc-Command D0 2 Main-Proc-Declaration E0 ::= I j N j true j false j nothing j g(E0*) E0* ::= j E0* E0 C0 ::= E0 j C01; C02 j if E01 then C01 else C02 fi D0 ::= j const I : T = E0 j D1 ; D2 Figure 16: Syntax of main procedure expressions, commands and declarations. All other syntax is as in the standard abstract syntax for . De nition 3.5 (H-environment, H-state) Let A be a -algebra and let H be a type environment. A value envionment, 2 ENV [A], is an H-environment if and only if for each I 2 dom(H), and for each type T , if H [[I ]] = T then [[I ]] 2 VALSAT . A state, ( ; ) is an H-state if and only if is an H-environment. The following lemma says that simulation relations are preserved by the evaluation of a main procedure expression in related states. Recall that we use let as a strict binding mechanism. Lemma 3.6 Let B and A be -algebras. Let R be a -simulation relation from B to A. Let H be a type environment. Then for all H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A] such that (dom B) (dom A), for each type T , for each main procedure expression E such that ;H ` E : T , for each identi er y : T , ( B; B)R ( A; A)) (let (vB; 0 B) = E [[E]] B ( B; B) in ([y 7! vB] B; 0 B)) R(let (vA; 0 A) = E [[E]] A ( A; A) in ([y 7! vA] A; 0 A)): Proof: (by induction on the structure of E). Let H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A] be given such that (dom B) (dom A). Let T and E be given such that ;H ` E : T . Let y : T be given. Suppose that ( B; B)R ( A; A). (basis) If E is an identi er I of type T , then the result follows from the assumption and the bindable property. If E is a numeral, N, or one of true, false, or nothing, then the result follows from the substitution property. (inductive step) Suppose that E has the form g(E*). Since g(E*) has type T , it must be that ;H ` E : ~ S and ResType(g; ~ S) = T , for some ~ S. The inductive hypothesis is that the lemma is true for each subexpression, Ei of type Si in the list E*. That is, 37 for all ( B;i 1; B;i 1) 2 STATE[B] and for all ( A;i 1; A;i 1) 2 STATE[A] such that (dom B;i 1) (dom A;i 1), for each type Si and for each expression Ei such that ;H ` Ei : Si, and for each identi er zi : Si, ( B;i 1; B;i 1)R ( A;i 1; A;i 1)) (let (di; B;i) = E [[Ei]] B ( B;i 1; B;i 1) in ([zi 7! di] B;i 1; B;i)) R(let (ei; A;i) = E [[Ei]] A ( A;i 1; A;i 1) in ([zi 7! ei] A;i 1; A;i)): The plan is to apply the inductive hypothesis for each expression in E*; for each i, binding the result of Ei to a distinct fresh identi er zi. If at any stage, one result is ?, then by the bistrict property, so is the other; otherwise the resulting states are related by the inductive hypothesis, and then the substitution property gives the desired result. The details are found in Appendix C. We do not know whether the converse of the above lemma holds. However, because the binding of the result of an expression to an identi er and a dynamic type check is what happens in the semantics of a constant declaration, the following corollary is immediate from the above lemma. Corollary 3.7 Let B and A be -algebras, and R be a -simulation relation from B to A. Let H be a type environment. For all H-states ( B; B) 2 STATE[B] and for all ( A; A) 2 STATE[A] such that (dom B) (dom A), for each main procedure declaration, D, such that ;H ` [[D]] =) H 0, (( B; B)R ( A; A))) (D [[D]] B ( B; B)) R (D [[D]] A ( A; A)): The following theorem extends the above lemma to show that simulation relations are preserved by main procedure commands in . Theorem 3.8 Let B and A be -algebras. Let R be a -simulation relation from B to A. Let H be a type environment. For all H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A], for all main procedure commands C such that C is well H-typed, ( B; B)R ( A; A)) (let 0 B = C [[C]] B ( B; B) in ( B; 0 B)) R(let 0 A = C [[C]] A ( A; A) in ( A; 0 A)) Proof: (by induction on the structure of C). Let H-states ( B; B) 2 STATE[B] and ( A; A) 2 STATE[A] be given. Let C be given such that C is well H-typed. Suppose that ( B; B)R ( A; A). (basis) Suppose that C is an expression, E. By Lemma 3.6, the result in one algebra is ? if and only if it is ? in the other. If the result is ?, the required property follows. Otherwise, let (vB; 0 B) = E [[E]] B ( B; B), and let (vA; 0 A) = E [[E]] A ( A; A). Then we can show the result as follows. ( B; B)R ( A; A) 38 ) hby Lemma 3.6i ([y 7! vB] B; 0 B)R ([y 7! vA] A; 0 A) ) hby shrinkable property of simulation relationsi ( B; 0 B)R ( A; 0 A) , hby de nition of command denotation of an expressioni (let 0 B = C [[E]] B ( B; B) in ( B; B0)) R (let 0 A = C [[E]] A ( A; A) in ( A; 0 A)) (inductive step) Assume, inductively, that the result holds for all subcommands of C. There are two cases. 1. Suppose C is \C1; C2". Then the result follows by two applications of the inductive hypothesis. 2. Suppose C is \if E then C1 else C2 fi". Let y : Bool be a fresh identi er. Again, by Lemma 3.6, the result of E is ? in one algebra if and only if it is ? in the other, and again if it is ? we are done. Otherwise, let (vB; 0 B) = E [[E]] B ( B; B) and (vA; 0 A) = E [[E]] A ( A; A). Then by the Lemma 3.6, ([y 7! vB] B; 0 B)R ([y 7! vA] A; 0 A): (21) Since Bool is a visible type, and R is EXTERNALS-identical, externValBBool(vB; 0 B) = externValABool(vA; 0 A): (22) Hence the result of the test is the same in both B and in A. So starting with Equation (21), the result is shown as follows. ([y 7! vB] B; 0 B)R ([y 7! vA] A; 0 A) ) hby the shrinkable property of simulation relationsi ( B; 0 B)R ( A; 0 A) ) hby the inductive hypothesis for C1 and C2i ((let 00 B = C [[C1]] B ( B; 0 B) in ( B; 00 B)) R (let 00 A = C [[C1]] A ( A; 0 A) in ( A; 00 A))) ^ ((let 00 B = C [[C2]] B ( B; 0 B) in ( B; 00 B)) R (let 00 A = C [[C2]] A ( A; 0 A) in ( A; 00 A))) , hby Equation (22)i (let 00 B = if externValBBool(vB; 0 B) then C [[C1]] B ( B; 0 B) else C [[C2]] B ( B; 0 B) in ( B; 00 B)) R (let 00 A = if externValABool(vA; 0 A) then C [[C1]] A ( A; 0 A) else C [[C2]] A ( A; 0 A) in ( A; 00 A)) , hby de nition of Ci (let 0 B = C [[if E then C1 else C2 fi]] B ( B; B) in ( B; 0 B)) R (let 0 A = C [[if E then C1 else C2 fi]] A ( A; A) in ( A; 0 A)) To summarize this section, with the split semantics one can investigate simulation relations between states using only the semantics of expressions, constant declarations, and commands in . The detailed semantics of type and method declarations are suppressed, because one only deals with their denotations: algebras of a given signature. 39 4 Related Work Our algebraic models are based, in part, on the work of Wing [73] and Chen [8]. These authors did not investigate simulation relations, or the use of mixed algebraic and denotational semantics. Several authors use Kripke (i.e., possible world) models to give semantics to mutation and object identities [18] [1] [72] [25]. One could consider our algebras to be Kripke models if we were to include the store as part of the algebra. However, we believe that keeping the store outside the algebra leads to a cleaner separation of the algebra and the semantics of . More importantly, it allows the denotational semantics to retain its characteristic referential transparency. Since Kripke models form a category, there are homomorphic functions on such models; however we do not know of anyone who has investigated relationships preserved by programs for Kripke models. For homomorphic relationships on Kripke models to be preserved by programs, the environment would also have to be included in the Kripke model, which would further destroy our separation between the language semantics and the semantics of the data types. Evolving algebras [21] [22] are algebraic structures whose operations may be updated. The relationship between our algebraic models and evolving algebras seems to be that our state plus our algebra is very similar to an evolving algebra. The di erences are that in giving a semantics to type and method declarations, the signature and everything else about our algebras changes, then in giving semantics to expressions and commands, only the state's environment and store can change. Once the type and method declarations are processed, in the \denotational half" of the semantics one can think of identifying the part of the Gurevich's algebra that evolves with our environment and store. Fixing one part of the \algebra" that evolves, namely not our algebra but our environment and store, makes our semantics more of a blend of denotational semantics and algebraic model theory than evolving algebras, as one can see by comparing our semantics with the evolving algebra semantics for C given in [23]. Action semantics [45] [71, Chapters 7{8] also uses algebraic techniques to specify data more abstractly than standard denotational semantics. However, in action semantics, the locations are not part of the algebra, and so the datatypes that one speci es must be immutable. Our semantic techniques allow one to obtain some of the bene ts of action semantics without adopting its idiosyncratic notation. The idea of computing over an algebra is also found in [66]. Our separation between the algebra and the semantics of is similar to what Mason and Talcott have studied the semantics of LISP [36] and other languages with mutation [37] [38]. Their work mainly uses operational semantics, and as such is complimentary to our denotational/algebraic approach. Mason and Talcott focus on equational logics for reasoning about programs that use mutation, whereas our work has not progressed to a reasoning calculus. 5 Future Work In view of the use of dynamic logic [26] in some of the related work on Kripke models [72] [25], it would be interesting to investigate the relationship between our techniques and dynamic logic. Perhaps dynamic logic or other related axiomatic speci cation techniques [6] would be useful in specifying our models, or in developing their theory. Another possibility is developing the theory more fully by de ning the appropriate category or institution [55]. 40 Another direction for future work is to extend our results to more interesting languages. We mentioned some language extensions that would be interesting for investigating the utility of the split semantics in Section 2.4 above. One could also extend our results about simulation relations to languages with higher types; that is, one could investigate logical relations that use something like our simulation relations for a base case. Our models have features for investigating observability notions, such as observable equivalence; we are trying to use these features to precisely de ne a notion of \observable aliasing" for objects of abstract data types [29]. But the main thrust of our investigations with these techniques is to extend our notions of legal behavioral subtyping in objectoriented programming to types with mutable objects [12] [13]. As a rst step, one could use something like our simulation relations to algebraically characterize when one set of ADTs with mutable objects implements another. 6 Conclusions The \split semantics" technique presented in this paper is a blend of algebraic and denotational semantics. We hope that it o ers some of the advantages of both techniques, and that it might prove bene cial when investigating the semantics of languages with ADTs and mutable objects. Our models of ADTs blend aspects of denotational semantics (locations, environment and store mappings) with traditional algebraic models. We believe that this blend gives a satisfactory foundation for the model theory of ADTs with mutation. In support of this we have o ered a notion of homomorphic relation (our simulation relations) and have shown that it is preserved by expressions and commands in a simple language. The addition of more realistic features to the language, such as loops, does not destroy this fundamental property [12] [13]. The semantics of the simple language, and the proof of this property demonstrate the utility of these techniques. When doing the proof, we ignored half the language's semantics, and started with the denotations of type and method declarations | that is, we started with our algebraic models and only used the (denotational-style) semantics of expressions and commands. Careful examination of our example algebras shows that models like ours could have been used to model mutable types long ago. All that is needed to equationally characterize mutable types is to adopt the old denotational semantics trick of explicitly passing a store around. This is another sense in which our models unify denotational and algebraic techniques. We believe that our approach to describing the semantics of languages with ADTs | the split semantics | is a fruitful way to do semantics for such languages. Traditional denotational semantics \compiles" the implementations of ADTs into an undi erentiated mass of functions, Cartesian products, etc. (For example, see [56].) The mess that results from this \compilation" process is di cult to compare to the speci cations of the abstract types, and di cult to extract from the rest of a program. This has made it di cult to apply the ideas of algebraic model theory to such languages, and has separated the worlds of algebraic and denotational semantics. By adding more structure to the semantics of a language with ADTs, that is, by compiling to an algebraic structure, one can have both a better organized semantics, and the possibility of using algebraic techniques to study the properties of either half of the language. 41 Acknowledgements Thanks to Carolyn Talcott and Ian Mason for electronic discussions, comments on an earlier draft, and references. Thanks to Jacek Lesczylowski and Uday Reddy for comments and discussions. Thanks to Yuri Gurevich for discussions about the relation of this work to evolving algebras. Thanks to Don Pigozzi for many discussions, which have been helpful in formulating these ideas. Thanks also to the students of \Programming Languges 1" (Com S 541) of Spring semester 1994, whose feedback on initial versions of this work helped us explain it better. Appendices A Postponed Proof Sketch for Lemma 3.3 The following is the proof sketch of Lemma 3.3, which was postponed from the text. Recall thatR0 is de ned in De nition 3.2, that D is de ned in Figure 5, and that the D-algebras D and E are de ned in Figures 7, 8, 12, and 13. Proof Sketch: Let ( E; E) 2 STATE[E], and ( D; D) 2 STATE[D] be given. The proof proceeds by showing that R0 has all the properties of a simulation relation. well-formed: By construction, R0 is well-formed. bindable: Let T be a type of D, let x : T be an identi er, and let y : T 2 (dom E) be given. Suppose that ( E; E)R0( D; D). We show that ([x 7! ( E y)] E; E)R0([x 7! ( D y)] D; D) by using the de nition ofR0. The only tricky part is to show that there is an injective graph homomorphism fromAliasG([x 7! ( E y)] E; E) toAliasG([x 7! ( D y)] D; D). By construction of R0, there is an injective graph homomorphism f = (fn; fe) from AliasG( E; E) to AliasG( D; D). We de ne the required injective graph homomorphism f 0 = (f 0 n; f 0 e) as follows. Let f 0 n def = [x 7! x]fn; that is, f 0 n(x) = x. If ( E y) = l and ( D y) = l0, then let f 0 e def = [(x; l) 7! (x; l0)]fe. By de nition, f 0 is a graph homomorphism. To show that f 0 is injective, we must show that f 0 n and f 0 e are injective. Since fn is injective and since fn is the identity on the identi ers in (dom E), f 0 n is injective. The following calculation shows that f 0 e is injective. Let u be any identi er, and lu be any location in LOCSE . (f 0 e (x; l)) = (f 0 e (u; lu)) ) hby the homomorphism propertyi ((f 0 n x); (f 0 n l)) = ((f 0 n u); (f 0 n lu)) ) hby de nition of equality for edgesi ((f 0 n x) = (f 0 n u))^ ((f 0 n l) = (f 0 n lu)) ) hby injectivity of f 0 ni (x = u) ^ (l = lu) bistrict: By construction, R0 is bistrict. substitution: To show that R0 satis es substitution property we must show it for all operations. The following example shows how the proof goes. The substitution property can be shown in a similar way for the other operations. The only signi cant di erence is for the mutator operations of Rect,where one must construct a new graph 42 homomorphism and show that it is injective. We take as our example the operation addX. We assume without loss of generality that the following hold. ( E p) = lPoint E ( D p) = lPoint D ( E i) = lInt E ( D i) = vInt D Let a type T and an identi er y : T be given. Suppose that ( E; E)R0 ( D; D): (23) Consider the results of the calling addX in each algebra. addXE(( E p; E i); E) def = addXE((lPoint E ; lInt E ); E) = let (l1; l2) = ( E lPoint) in let (lnew ; 0 E) = addE((l1; lInt E ); E) in ( ; [lPoint E 7! (lnew ; l2)] 0 E) addXD(( D p; D i); D) = addXD((lPoint D ; vInt D ); D) def = let (v1; v2) = ( D lPoint D ) in ( ; [lPoint D 7! (v1 + vInt D ; v2)] D) If the result of calling addX in E is ?, this can only be because lPoint E , l1, or lInt E is not in the domain of E. If lPoint E 62 dom( E), then by de nition of R0, in particular the de nition of S 0 Point, it must be that lPoint D 62 dom( D). Similarly using the de nition of S 0, one can show that if the result of calling addX in E is ?, then the result of calling addX in D must also be ?. If both are ?, then the substitution property holds; so we need not consider this case further. The remaining case is if the result of calling addX in E is proper. There are two subcases: one is when the result in D is ?, and the other when the result in D is proper. Suppose the result inD is ?. Then by de nition ofD, it must be that lPoint D 62 dom( D), but then by de nition of S 0, lPoint E 62 dom( E), which is a contradiction, because (it is now assumed) the result of calling addX in E is proper. Hence it must be that, in this case, both results are proper. In the case that both results are proper, we use Er and Dr to refer to the stores in these nal (or result) states, i.e., E;r = [lPoint E 7! (lnew ; l2)] 0 E and D;r = [lPoint D 7! (v1 + vInt D ; v2)] D. We will also refer to the store 0 E to refer to the intermediate store de ned in the course of evaluating addXE(( E p; E i); E). With this notation, what we have to show for the substitution property is as follows. ([y 7! ] E; Er)R0 ([y 7! ] D; Dr) (24) We show that this holds by showing that it satis es each of the properties in the de nition of R0. By hypothesis, (dom E) (dom D), and thus (dom ([y 7! ] E)) (dom ([y 7! ] D)): 43 To show that the abstract values for each identi er are similar in the nal states, let T be a type and let z : T be an identi er in (dom ([y 7! ] E)). We do this by cases. { Suppose that there is no path from z to lPoint E in the graph AliasG( E; E). Then the abstract value of z is unchanged. Hence, by the hypothesis: S 0 T ( Er ; Dr)(( E z); ( D z)): (25) { If z is p : Point, we need to show S 0 Point( Er ; Dr)( E p; D p)). It su ces to show the following two conditions, where the names of the locations and values are as in the de ning expressions for the result states. S0 Int( 0 E; D)(lnew ; v1 + vInt D ) (26) S0 Int( 0 E; D)(l2; v2) (27) Condition (27) holds by hypothesis, which implies that the abstract values of p are related by S 0 Int in the original states. Condition (26) follows from the de nition of addE, and the relationships of the abstract values in the original states. { Otherwise z is an identi er that is not p, but from which p is reachable along some path of AliasG( E; E). Note that AliasG([y 7! ] E; Er) = AliasG( E; E), because the environments in the result state only di er by the binding of y, which does not create any edges, and because of the de nition of addX in both algebras. If T , the type of z, is Point then z and pmust denote the same location in [y 7! ] E. The same situation must hold in [y 7! ] E, because there is a homomorphism fromAliasG([y 7! ] E; Er) toAliasG([y 7! ] D; Dr). Since z denotes the same location as p in both nal states, the above argument shows that the abstract values of z are similar. If T is Rect, then one (or both!) of the corners of z is the same location as denoted by p. Again, the graph homomorphism on the aliasing graphs ensures that the same situation holds in both algebras, and thus the abstract values are similar. To show that there is an injective graph homomorphism on the result states, we observe that by de nition of R0 and the hypothesis, there is an injective homomorphism f = (fn; fe) from AliasG( E; E) to AliasG( D; D). We construct a new injective homomorphism f 0 = (f 0 n; f 0 e) from AliasG([y 7! ] E; Er) to AliasG([y 7! ] D; Dr) by simply letting f 0 n = fn and f 0 e = fe. This su ces because the only new identi er does not have a type that matters, and because no new locations of type Point or Rect are introduced. shrinkable: That R0 satis es the shrinkable property follows in a straightforward manner from its de nition. EXTERNALS-identical: That R0 satis es the EXTERNALS-identical property follows from basis of the de nition of S 0. 44 [ident] ;H ` I : T if H [[I ]] = T [numeral] ;H ` N : Int [true] ;H ` true : Bool [false] ;H ` false : Bool [nothing] ;H ` nothing : Void [method call] ;H ` E : ~ S; ` ResType(g; ~ S) = T ;H ` g(E*) : T [empty decl] ;H ` [[]] =) emptyEnviron [const decl] ;H ` E : T ;H ` [[const I:T = E]] =) [I 7! T ]H [decls] ;H ` [[D1]] =) H1; ;H ` [[D2]] =) H2 ;H ` [[D1; D2]] =) H2 Figure 17: Type Inference Rules for main procedure expressions and rules for inferring type environments for constant declarations. B Types of Main Procedure Expressions and Declarations Formal type inference rules for main procedure expressions and declarations are given in Figure 17. In the gure, H is a type environment, which is a nite function from identi ers to types. Such a type environment is produced by constant declarations; the formal rules for deriving a type environment from a constant declaration are given in the gure. The notation ` ResType(g; ~ S) = T indicates that ResType comes from . C Omitted Details of the Proof of Lemma 3.6 The following proof has the omitted details for lemma 3.6. It picks up in the inductive step right where the proof in the main text leaves o . Proof: Let the zi : Si be distinct identi ers. We construct new states ( B;n; B;n) and ( A;n; A;n) such that the following hold for each 1 i n: (d̂n; B;n) = E [[E*]] B ( B; B) (28) B;n(zi) = (productize d̂n) # i (29) (ên; A;n) = E [[E*]] A ( A; A) (30) A;n(zi) = (productize ên) # i (31) 45 ( B;n; B;n) R ( A;n; A;n)(32)Once this is done, we can calculate as follows.E [[g(E*)]] B ( B; B)= hby de nition of E and B;nilet (d̂n; B;n) = E [[E*]] B ( B; B) in gB((productize d̂n); B;n)= hby de nition of B;nilet (d̂n; B;n) = E [[~z]] B ( B;n; B;n) in gB((productize d̂n); B;n)= hby de nition of EiE [[g(~z)]] B ( B;n; B;n)Similarly,E [[g(~z)]] A ( A;n; A;n) = E [[g(E*)]] A ( A; A):Therefore, by the substitution property and Equation (32), the desired result follows.(let (vB; 0B) = E [[g(E*)]] B ( B; B) in ([y 7! vB] B; 0B))R(let (vA; 0A) = E [[g(E*)]] A ( A; A) in ([y 7! vA] A; 0A))(33)So it remains to construct the states ( B;n; B;n) and ( A;n; A;n) and the lists d̂n andên with the required properties. These are constructed by induction on n. The constructiononly mentions the case where all the subexpressions have proper results; if at any stage oneof the subexpressions has ? for a result in one algebra, by the bistrictness of R it must alsobe ?, in the other, and then by the de nition of , the required relationship would hold.For the basis, if n = 0, then E* is empty, so let ( B;0; B;0) = ( B; B), ( A;0; A;0) =( A; A), d̂0 = nil , and ê0 = nil . The required properties hold trivially.For the inductive step, suppose that E* is E1 Ej 1 Ej and further suppose that( B;j 1; B;j 1), ( A;j 1; A;j 1), d̂j 1, and êj 1 satisfy the required properties. The re-quired stores, along with values that will be used shortly, are constructed as follows.(dj ; B;j) def= E [[Ej ]] B ( B;j 1; B;j 1)(34)(ej ; A;j) def= E [[Ej ]] A ( A;j 1; A;j 1):(35)We de ne the required environments and lists as follows.d̂j def= (addToEnd d̂j 1 dj)(36)êj def= (addToEnd êj 1 ej)(37)B;j def= [zj 7! dj ] B;j 1(38)A;j def= [zj 7! ej ] A;j 1:(39)The properties required of the constructed states and lists are veri ed as follows. Toshow that d̂j and B;j have the required properties we calculate as follows.E [[E1 Ej 1 Ej ]] B ( B; B)= hby de nition of E and inductive hypothesisilet (dj; B;j) = E [[Ej]] B ( B; B;j 1) in (addToEnd d̂j 1 dj); B;j)46 = hby by de nition of (d̂j; B;j)i(d̂j ; B;j)Similarly, êj and A;j have the required properties.Let 1 i j be given. Then we can verify the required property of B;j as follows.B;j(zi)= hby de nition of B;j and environment extensioniif (zi = zj) then dj else B;j 1(zi)= hby inductive hypothesis for B;j 1 and d̂j 1iif (zi = zj) then dj else productize(d̂j 1) # i= hby distinctness of the zkiif (i = j) then dj else productize(d̂j 1) # i= hby Equation (13), i.e., the de ning property of productize and addToEndi(productize(addToEnd d̂j 1 dj)) # i= hby construction of d̂ji(productize d̂j) # iSimilarly, A;j has the required property.Equation (32) thus follows directly from the main inductive hypothesis, because of theinductive assumption that ( B;j 1; B;j 1)R( A;j 1; A;j 1).References[1] A. J. Alencar and J. A. Goguen. OOZE: An object oriented Z environment. In P. Amer-ica, editor, ECOOP '91: European Conference on Object Oriented Programming, vol-ume 512 of Lecture Notes in Computer Science, pages 180{199. Springer-Verlag, NewYork, N.Y., 1991.[2] Pierre America. Inheritance and subtyping in a parallel object-oriented language. InJean Bezivin et al., editors, ECOOP '87, European Conference on Object-OrientedProgramming, Paris, France, pages 234{242, New York, N.Y., June 1987. Springer-Verlag. Lecture Notes in Computer Science, Volume 276.[3] Pierre America. Designing an object-oriented programming language with behaviouralsubtyping. In J. W. de Bakker, W. P. de Roever, and G. Rozenberg, editors, Foun-dations of Object-Oriented Languages, REX School/Workshop, Noordwijkerhout, TheNetherlands, May/June 1990, volume 489 of Lecture Notes in Computer Science, pages60{90. Springer-Verlag, New York, N.Y., 1991.[4] H. P. Barendregt. The Lambda Calculus: Its Syntax and Semantics. North-HollandPublishing Co., New York, N.Y., 1984. Revised Edition.[5] M. Bidoit, H.-J. Kreowski, P. Lescanne, F. Orejas, and D. Sannella, editors. AlgebraicSystem Speci cation and Development: A Survey and Annotated Bibliography, volume501 of Lecture Notes in Computer Science. Springer-Verlag, 1991. ISBN 0-387-54060-1.[6] Hans-Juergen Boehm. Side e ects and aliasing can have simple axiomatic descriptions.ACM Transactions on Programming Languages and Systems, 7(4):637{655, October1985.47 [7] Kim B. Bruce and Peter Wegner. An algebraic model of subtype and inheritance. InFrancois Bancilhon and Peter Buneman, editors, Advances in Database ProgrammingLanguages, pages 75{96. Addison-Wesley, Reading, Mass., August 1990.[8] Jolly Chen. The Larch/Generic interface language. Technical report, MassachusettsInstitute of Technology, EECS department, May 1989. The author's Bachelor's thesis.Available from John Guttag at MIT ([email protected]).[9] A. Church. The Calculi of Lambda Conversion, volume 6 of Annals of MathematicsStudies. Princeton University Press, Princeton, N.J., 1941. Reprinted by Klaus ReprintCorp., New York in 1965.[10] William R. Cook. A denotational semantics of inheritance. Technical Report CS-89-33,Department of Computer Science, Brown University, Providence, Rhode Island, May1989.[11] N. G. de Bruijn. A survey of the project automath. In J. P. Seldin and J. R. Hind-ley, editors, To H. B. Curry: Essays on Combinatory Logic, Lambda Calculus andFormalism, pages 579{606. Academic Press, Inc., New York, N.Y., 1980.[12] Krishna Kishore Dhara. Subtyping among mutable types in object-oriented program-ming languages. Master's thesis, Iowa State University, Department of ComputerScience, Ames, Iowa, May 1992.[13] Krishna Kishore Dhara and Gary T. Leavens. Subtyping for mutable types in object-oriented programming languages. Technical Report 92-36, Department of ComputerScience, Iowa State University, Ames, Iowa, 50011, November 1992. Available byanonymous ftp from ftp.cs.iastate.edu, and by e-mail from [email protected].[14] Hartmut Ehrig and Bernd Mahr. Fundamentals of Algebraic Speci cation 1: Equa-tions and Initial Semantics. EATCS Monographs on Theoretical Computer Science.Springer-Verlag, New York, N.Y., 1985.[15] J. A. Goguen, J. W. Thatcher, and E. G. Wagner. An initial algebra approach to thespeci cation, correctness and implementation of abstract data types. In Raymond T.Yeh, editor, Current Trends in Programming Methodology, volume 4, pages 80{149.Prentice-Hall, Inc., Englewood Cli s, N.J., 1978.[16] J. A. Goguen, J. W. Thatcher, E. G. Wagner, and J. B. Wright. Initial algebra seman-tics and continuous algebras. Journal of the ACM, 24:68{95, 1977.[17] Joseph A. Goguen. Realization is universal. Math. Systems Theory, 6(4):359{374, 1973.[18] Joseph A. Goguen and Jos e Meseguer. Unifying functional, object-oriented and rela-tional programming with logical semantics. In Bruce Shriver and Peter Wegner, editors,Research Directions in Object-Oriented Programming, pages 417{477. The MIT Press,Cambridge, Mass., 1987.[19] Adele Goldberg and David Robson. Smalltalk-80, The Language and its Implementa-tion. Addison-Wesley Publishing Co., Reading, Mass., 1983.[20] I. Guessarian. Algebraic Semantics, volume 99 of Lecture Notes in Computer Science.Springer-Verlag, New York, N.Y., 1981.48 [21] Yuri Gurevich. Evolving algebras: A tutorial introduction. Bulletin of the EATCS,43:264{284, February 1991.[22] Yuri Gurevich. Evolving algebras: An attempt to discover semantics. In G. Rozenbergand A. Salomaa, editors, Current Trends in Theoretical Computer Science, pages 266{292. World Scienti c, 1993.[23] Yuri Gurevich and James K. Huggins. The semantics of the c programming language.In E. Borger et al., editors, Computer Science Logic, Proceedings, 1992, volume 702 ofLecture Notes in Computer Science, pages 274{308. Springer-Verlag, New York, N.Y.,1992. Errata to appear in the 1993 Computer Science Logic proceedings. Correctedcopy obtained from the authors.[24] C. A. R. Hoare. Proof of correctness of data representations. Acta Informatica,1(4):271{281, 1972.[25] R. Jungclaus, G. Saake, and C. Sernadas. Formal speci cation of object systems. InS. Abramsky and T. S. E. Maibaum, editors, TAPSOFT '91, Proceedings of the Inter-national Joint Conference on Theory and Practice of Software Development, Brighton,UK, Volume 2, Advances in Distributed Computing (ADC) and Colloquium on Com-bining Paradigms for Software Development (CCPSD), volume 494 of Lecture Notes inComputer Science, pages 60{82. Springer-Verlag, New York, N.Y., April 1991.[26] Dexter Kozen and J. Tiuryn. Logics of programs. In J. van Leewen, editor, Handbookof Theoretical Computer Science, volume B: Formal Models and Semantics, chapter 14,pages 789{840. The MIT Press, New York, N.Y., 1990.[27] Gary T. Leavens. Modular veri cation of object-oriented programs with subtypes.Technical Report 90-09, Department of Computer Science, Iowa State University,Ames, Iowa, 50011, July 1990. Available by anonymous ftp from ftp.cs.iastate.edu,and by e-mail from [email protected].[28] Gary T. Leavens. Modular speci cation and veri cation of object-oriented programs.IEEE Software, 8(4):72{80, July 1991.[29] Gary T. Leavens and Krishna Kishore Dhara. A foundation for the model theoryof abstract data types with mutation and aliasing (preliminary version). TechnicalReport 92-35, Department of Computer Science, Iowa State University, Ames, Iowa,50011, November 1992. Available by anonymous ftp from ftp.cs.iastate.edu, and bye-mail from [email protected].[30] Gary T. Leavens and Don Pigozzi. Typed homomorphic relations extended with sub-types. Technical Report 91-14, Department of Computer Science, Iowa State Uni-versity, Ames, Iowa, 50011, June 1991. Appears in the proceedings of MathematicalFoundations of Programming Semantics '91, Springer-Verlag, Lecture Notes in Com-puter Science, volume 598, pages 144-167, 1992.[31] Gary T. Leavens and Don Pigozzi. Typed homomorphic relations extended with sub-types. In Stephen Brookes, editor, Mathematical Foundations of Programming Seman-tics '91, volume 598 of Lecture Notes in Computer Science, pages 144{167. Springer-Verlag, New York, N.Y., 1992.49 [32] Gary T. Leavens and William E.Weihl. Reasoning about object-oriented programs thatuse subtypes (extended abstract). ACM SIGPLAN Notices, 25(10):212{223, October1990. OOPSLA ECOOP '90 Proceedings, N. Meyrowitz (editor).[33] Gary T. Leavens and William E. Weihl. Subtyping, modular speci cation, and mod-ular veri cation for applicative object-oriented programs. Technical Report 92-28d,Department of Computer Science, Iowa State University, Ames, Iowa, 50011, August1994. Available by anonymous ftp from ftp.cs.iastate.edu, and by e-mail from [email protected].[34] Gary Todd Leavens. Verifying Object-Oriented Programs that use Subtypes. PhD thesis,Massachusetts Institute of Technology, December 1988. Published as MIT/LCS/TR-439 in February 1989.[35] Barbara H. Liskov and Stephen N. Zilles. Speci cation techniques for data abstraction.Transactions on Software Engineering, 1(1), March 1975.[36] I. A. Mason. The Semantics of Destructive Lisp. PhD thesis, Stanford University,1986. Also available as CSLI Lecture Notes No. 5, Center for the Study of Languageand Information, Stanford University.[37] Ian Mason and Carolyn Talcott. Equivalence in functional languages with e ects.Journal of Functional Programming, 1(3):287{328, July 1991.[38] Ian A. Mason and Carolyn L. Talcott. References, local variables and operationalreasoning. In Seventh Annual Symposium on logic in computer science. IEEE, 1992.[39] Albert R. Meyer and Kurt Sieber. Towards fully abstract semantics for local variables:Preliminary report. In Proc. 15th Annual ACM Symp. on Principles of ProgrammingLanguages, San Diego, pages 191{203. ACM, 1988.[40] Bertrand Meyer. Object-oriented Software Construction. Prentice Hall, New York,N.Y., 1988.[41] Robin Milner, Mads Tofte, and Robert Harper. The De nition of Standard ML. TheMIT Press, Cambridge, Mass., 1990.[42] John C. Mitchell. Type systems for programming languages. In J. van Leeuwen, editor,Handbook of Theoretical Computer Science, volume B: Formal Models and Semantics,chapter 8, pages 365{458. North-Holland, New York, N.Y., 1990.[43] B. Moller. On the algebraic speci cation of in nite objects|ordered and continuousmodels of algebraic types. Acta Informatica, 22:537{578, 1985.[44] Peter D. Mosses. Denotational semantics. In J. van Leewen, editor, Handbook ofTheoretical Computer Science, volume B: Formal Models and Semantics, chapter 11,pages 577{631. The MIT Press, New York, N.Y., 1990.[45] Peter D. Mosses. Action Semantics, volume 26 of Cambridge Tracts in TheoreticalComputer Science. Cambridge University Press, New York, N.Y., 1992.[46] Tobias Nipkow. Non-deterministic data types: Models and implementations. ActaInformatica, 22(16):629{661, March 1986.50 [47] P. W. O'Hearn and R. D. Tennent. Semantics of local variables. In M. P. Fourman,P. T. Johnstone, and A. M. Pitts, editors, Applications of Categories in ComputerScience, volume 177 of London Mathematical Society Lecture Note Series, pages 217{238. Cambridge University Press, Cambridge, England, 1992.[48] Peter W. O'Hearn and Robert D. Tennent. Relational parametricity and local variables.In Proc. 20th Annual ACM Symposium on Principles of Programming Languages, pages171{184, 1993.[49] D. L. Parnas. A technique for the speci cation of software modules with examples.Communications of the ACM, 15(5):330{336, May 1972.[50] Laurence C. Paulson. ML for the Working Programmer. Cambridge University Press,New York, N.Y., 1991.[51] F. Parisi Presicce and A. Pierantonio. An algebraic view of inheritance and subtyp-ing in object oriented programming. In A. van Lamsweerde and A. Fugetta, editors,ESEC '91: 3rd European Software Engineering Conference, Milan, Italy, volume 550of Lecture Notes in Computer Science, pages 364{379. Springer-Verlag, October 1991.[52] Uday S. Reddy. Passivity and independence. In Proceedings Ninth Annual IEEESymposium on Logic in Computer Science, Paris, France, pages 342{352. IEEE, July1994.[53] John C. Reynolds. Using category theory to design implicit conversions and genericoperators. In Neil D. Jones, editor, Semantics-Directed Compiler Generation, Pro-ceedings of a Workshop, Aarhus, Denmark, volume 94 of Lecture Notes in ComputerScience, pages 211{258. Springer-Verlag, January 1980.[54] John C. Reynolds. Three approaches to type structure. In Hartmut Ehrig, Chris-tiane Floyd, Maurice Nivat, and James Thatcher, editors, Mathematical Foundationsof Software Development, Proceedings of the International Joint Conference on Theoryand Practice of Software Development (TAPSOFT), Berlin. Volume 1: Colloquiumon Trees in Algebra and Programming (CAAP '85), volume 185 of Lecture Notes inComputer Science, pages 97{138. Springer-Verlag, New York, N.Y., March 1985.[55] Donald Sannella and Andrzej Tarlecki. Speci cations in an arbitrary institution. Infor-mation and Computation, 76(2/3):165{210, February/March 1988. A revised versionof the paper that appeared in the 1984 Semantics of Data Types Symposium, LNCS173, pages 337{356.[56] Schei er. A denotational semantics of CLU. Technical Report TR-201, MassachusettsInstitute of Technology, Laboratory for Computer Science, May 1978.[57] David A. Schmidt. Denotational Semantics: A Methodology for Language Development.Allyn and Bacon, Inc., Boston, Mass., 1986.[58] David A. Schmidt. The Structure of Typed Programming Languages. Foundations ofComputing Series. MIT Press, Cambridge, Mass., 1994.[59] Oliver Schoett. Behavioural correctness of data representations. Science of ComputerProgramming, 14(1):43{57, June 1990. 51 [60] Oliver Schoett. An observational subset of rst-order logic cannot specify the be-havior of a counter. In C. Cho rut and M. Jantzen, editors, STACS 91 8th AnnualSymposium on Theoretical Aspects of Computer Science Hamburg, Germany, February1991 Proceedings, volume 480 of Lecture Notes in Computer Science, pages 499{510.Springer-Verlag, New York, N.Y., 1991.[61] K. Sieber. Call-by-value and non-determinism. In M. Bezem and J.F. Groote, editors,International Conference on Typed Lambda Calculi and Applications, number 664 inLecture Notes in Computer Science, pages 376{390, Utrecht, The Netherlands, March1993. Springer-Verlag. TLCA'93.[62] Kurt Sieber. Reasoning about sequential functions via logical relations. In M. P. Four-man, P. T. Johnstone, and A. M. Pitts, editors, Proc. LMS Symposium on Applicationsof Categories in Computer Science, Durham 1991, LMS Lecture Note Series 177, pages258{269. Cambridge University Press, 1992.[63] Kurt Sieber. New steps towards full abstraction for local variables. In Proc. ACMSIGPLAN Workshop on State in Programming Languages, pages 88{100, Copenhagen,Denmark, 1993. Published as Yale University, Dept. of Comp. Sci. Technical ReportYALEU/DCS/RR-968.[64] J. Stoy. Denotational Semantics: The Scott-Strachey Approach to Programming Lan-guage Theory. The MIT Press, Cambridge, Mass., 1977.[65] R. D. Tennent. Correctness of data representations in Algol-like languages. In A. W.Roscoe, editor, A Classical Mind, Essays in Honour of C. A. R. Hoare, chapter 23,pages 405{417. Prentice-Hall International, 1994.[66] J. V. Tucker and J. I. Zucker. Toward a general theory of computation and speci ca-tion over abstract data types. In S. G. Akl, F. Fiala, and W. W. Koczkodaj, editors,Advances in Computing and Information ICCI '90, International Conference on Com-puting and Information, Niagara Falls, Canada, May 1990, volume 468 of LectureNotes in Computer Science, pages 129{133. Springer-Verlag, New York, N.Y., 1991.[67] Mark Utting. An Object-Oriented Re nement Calculus with Modular Reasoning. PhDthesis, University of New South Wales, Kensington, Australia, 1992. Draft of February1992 obtained from the Author.[68] Mark Utting and Ken Robinson. Modular reasoning in an object-oriented re nementcalculus. In R. S. Bird, C. C. Morgan, and J. C. P. Woodcock, editors, Mathematicsof Program Construction, Second International Conference, Oxford, U.K., June/July,volume 669 of Lecture Notes in Computer Science, pages 344{367. Springer-Verlag,New York, N.Y., 1992.[69] Philip Wadler and Stephen Blott. How to make ad-hoc polymorphism less ad hoc.In Conference Record of the Sixteenth Annual ACM Symposium on Principles of Pro-gramming Languages, Austin, Texas, pages 60{76. ACM, January 1989.[70] E. G.Wagner, J. W. Thatcher, and J. B. Wright. Programming languages as mathemat-ical objects. In J. Winkowski, editor, Mathematical Foundations of Computer Science,volume 10 of Lecture Notes in Computer Science, pages 84{101. Springer-Verlag, NewYork, N.Y., 1978.52 [71] David A. Watt. Programming Language Syntax and Semantics. Prentice Hall Interna-tional Series in Computer Science. Prentice-Hall, New York, N.Y., 1991.[72] R. J. Wieringa. A formalization of objects using equational dynamic logic. In C. De-lobel, M. Kifer, and Y. Masanaga, editors, Deductive and object-Oriented Databases,volume 566 of Lecture Notes in Computer Science, pages 431{452. Springer-Verlag,New York, N.Y., 1991.[73] Jeannette Marie Wing. A two-tiered approach to specifying programs. Technical Re-port TR-299, Massachusetts Institute of Technology, Laboratory for Computer Science,1983.[74] Martin Wirsing. Algebraic speci cation. In J. van Leewen, editor, Handbook of Theo-retical Computer Science, volume B: Formal Models and Semantics, chapter 13, pages675{788. The MIT Press, New York, N.Y., 1990.

برای دانلود رایگان متن کامل این مقاله و بیش از 32 میلیون مقاله دیگر ابتدا ثبت نام کنید

ثبت نام

اگر عضو سایت هستید لطفا وارد حساب کاربری خود شوید

منابع مشابه

Blended Algebraic and Denotational Semantics for ADT Languages with Mutable Objects

This paper presents a semantics for a simple language that is a blend of algebraic models and traditional denotational semantics. In this semantics, implementations of user-de ned abstract data types are \compiled" into an algebraic structure, which is used by the denotational part of the semantics whenever an operation of the data type is invoked. To show the utility of such a semantics, an al...

متن کامل

Semantic Lego

Denotational semantics [Sch86] is a powerful framework for describing programming languages; however, its descriptions lack modularity: conceptually independent language features in uence each others' semantics. We address this problem by presenting a theory of modular denotational semantics. Following Mosses [Mos92], we divide a semantics into two parts, a computation ADT and a language ADT (a...

متن کامل

An Indexed Model of Impredicative Polymorphism and Mutable References

We present a semantic model of the polymorphic lambda calculus augmented with a higher-order store, allowing the storage of values of any type, including impredicative quantified types, mutable references, recursive types, and functions. Our model provides the first denotational semantics for a type system with updatable references to values of impredicative quantified types. The central idea b...

متن کامل

Dialgebraic Semantics of Typed Object Calculi

Algebraic data type theory has a notion of structural recursion. Coalgebraic data types similarly have a notion of structural corecursion. In this thesis we study a third form of recursion: direcursion. The other two notions have been used in program derivations, correctness proofs, and in foundations of functional and class-based languages. Direcursion, on the other hand, has not been extensiv...

متن کامل

A Theory of Symbolic Dynamics for Hybrid Systems

In this paper, we introduce a new semantics for hybrid systems called symbolic dynamics. The semantics is constructed in the tradition of denotational semantics of programming languages, which defines the meaning of a construct by a function. The novelty of this approach is that these semantic functions are defined on complex state spaces carrying algebraic and analytic structures. As in the de...

متن کامل

Continuations for Remote Objects Control

We have recently introduced the ”continuation semantics for concurrency” (CSC) technique in an attempt to exploit the benefits of using continuations in concurrent systems development. CSC is a general technique for denotational semantics which provides excellent flexibility in the compositional modeling of concurrent control concepts. In this paper, we present a denotational semantics designed...

متن کامل

ذخیره در منابع من


  با ذخیره ی این منبع در منابع من، دسترسی به آن را برای استفاده های بعدی آسان تر کنید

عنوان ژورنال:

دوره   شماره 

صفحات  -

تاریخ انتشار 1994